Rust 에서 효율적인 파일 읽기

Beginner

This tutorial is from open-source community. Access the source code

소개

이 실습에서는 Rust 에서 파일에서 라인을 읽는 데 대한 단순 구현과 더 효율적인 구현을 제공합니다. 단순한 방법은 파일을 하나의 문자열로 읽어 read_to_string을 사용하고, 그런 다음 라인으로 분할하는 반면, 더 효율적인 방법은 전체 내용을 메모리에 로드하지 않고 파일을 라인 단위로 읽는 BufReader를 사용합니다.

참고: 실습에서 파일 이름을 지정하지 않으면 원하는 파일 이름을 사용할 수 있습니다. 예를 들어 main.rs를 사용하고 rustc main.rs && ./main으로 컴파일 및 실행할 수 있습니다.

read_lines

단순한 방법

파일에서 라인을 읽는 초보자의 첫 번째 구현에 대한 합리적인 첫 시도일 수 있습니다.

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() 메서드는 파일의 라인에 대한 반복자를 반환하므로, 인라인 매핑을 수행하고 결과를 수집하여 더 간결하고 유창한 표현을 얻을 수도 있습니다.

use std::fs::read_to_string;

fn read_lines(filename: &str) -> Vec<String> {
    read_to_string(filename)
        .unwrap()  // 파일 읽기 오류 발생 시 즉시 종료
        .lines()  // 문자열을 문자열 슬라이스 반복자로 분할
        .map(String::from)  // 각 슬라이스를 문자열로 변환
        .collect()  // 벡터에 모음
}

위의 두 예제에서 lines()가 반환하는 &str 참조를 각각 .to_string()String::from을 사용하여 소유형 String으로 변환해야 함에 유의하십시오.

더 효율적인 방법

여기서는 열린 File의 소유권을 BufReader 구조체에 전달합니다. BufReader는 내부 버퍼를 사용하여 중간 할당을 줄입니다.

또한 read_lines를 업데이트하여 각 라인에 대한 메모리에 새로운 String 객체를 할당하는 대신 반복자를 반환합니다.

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") {
        // 반복자를 소비하고 (선택적) 문자열을 반환합니다.
        for line in lines {
            if let Ok(ip) = line {
                println!("{}", ip);
            }
        }
    }
}

// 출력은 오류 일치를 허용하기 위해 Result 로 감싸져 있습니다.
// 파일의 라인의 Reader 에 대한 반복자를 반환합니다.
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>를 인수로 예상하기 때문에 where 키워드를 사용하여 동일한 제네릭 제약 조건을 가진 제네릭 read_lines() 메서드를 정의했습니다.)

이 프로세스는 파일의 모든 내용으로 메모리에 String을 만드는 것보다 더 효율적입니다. 이는 특히 큰 파일을 처리할 때 성능 문제를 일으킬 수 있습니다.

요약

축하합니다! Read_lines 실습을 완료했습니다. LabEx 에서 더 많은 실습을 통해 기술을 향상시킬 수 있습니다.