Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

read_lines

단순한 접근 방식

이는 초보자가 파일에서 줄을 읽기 위해 처음 시도해 볼 만한 합리적인 방식일 수 있습니다.

#![allow(unused)]
fn main() {
use std::fs::read_to_string;

fn read_lines(filename: &str) -> Vec<String> {
    let mut result = Vec::new();

    for line in read_to_string(filename).unwrap().lines() {
        result.push(line.to_string())
    }

    result
}
}

lines() 메서드가 파일의 줄들에 대한 이터레이터를 반환하므로, 인라인에서 map을 수행하고 결과를 collect하여 더 간결하고 유려한 표현식을 만들 수도 있습니다.

#![allow(unused)]
fn main() {
use std::fs::read_to_string;

fn read_lines(filename: &str) -> Vec<String> {
    read_to_string(filename)
        .unwrap()  // 발생 가능한 파일 읽기 에러에 대해 패닉을 일으킵니다
        .lines()  // 문자열을 문자열 슬라이스 이터레이터로 분할합니다
        .map(String::from)  // 각 슬라이스를 String으로 만듭니다
        .collect()  // 이들을 벡터로 모읍니다
}
}

위의 두 예제 모두에서, lines()가 반환한 &str 참조를 .to_string() 또는 String::from을 사용하여 소유형인 String으로 변환해야 한다는 점에 유의하세요.

더 효율적인 접근 방식

여기서는 열려 있는 File의 소유권을 BufReader 구조체로 넘깁니다. BufReader는 내부 버퍼를 사용하여 중간 할당을 줄입니다.

또한 각 줄마다 메모리에 새로운 String 객체를 할당하는 대신 이터레이터를 반환하도록 read_lines를 업데이트합니다.

use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;

fn main() {
    // hosts.txt 파일이 현재 경로에 존재해야 합니다
    if let Ok(lines) = read_lines("./hosts.txt") {
        // 이터레이터를 소비하여, (선택적인) String을 반환합니다
        for line in lines.map_while(Result::ok) {
            println!("{}", line);
        }
    }
}

// 에러에 대한 매칭이 가능하도록 출력을 `Result`로 감쌉니다.
// 파일의 각 줄을 읽어오는 이터레이터를 반환합니다.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}

이 프로그램을 실행하면 단순히 각 줄을 개별적으로 출력합니다.

$ echo -e "127.0.0.1\n192.168.0.1\n" > hosts.txt
$ rustc read_lines.rs && ./read_lines
127.0.0.1
192.168.0.1

(File::open이 인자로 제네릭 AsRef<Path>를 요구하므로, 우리의 제네릭 read_lines() 메서드도 where 키워드를 사용하여 동일한 제네릭 제약 조건을 정의한다는 점에 유의하세요.)

이 과정은 파일의 모든 내용을 메모리에 String으로 생성하는 것보다 효율적입니다. 특히 대용량 파일을 다룰 때 메모리에 모두 올리는 방식은 성능 문제를 일으킬 수 있습니다.