본문으로 건너뛰기

안동민 개발노트

본문 시작

파일 읽기

명령줄에서 받은 경로의 텍스트 파일을 읽어 출력하고 존재하지 않거나 읽을 수 없는 파일의 실패 경로를 확인합니다.

이제는 file_path 인수에 명시된 파일을 읽는 기능을 추가해보겠습니다.

우선 테스트에 사용할 샘플 파일이 필요합니다.

여러 줄의 몇 개의 반복된 단어들로 구성된 작은 양의 텍스트로 된 파일을 사용하겠습니다.

예제 11-3은 딱 맞게 사용될 에밀리 딕킨슨(Emily Dickinson)의 시가 있습니다!

프로젝트의 루트 레벨에 poem.txt이라는 이름의 파일을 만들고, 시 ‘I’m Nobody! Who are you?’를 입력하세요.

예제 11-3: 에밀리 딕킨슨의 시는 좋은 테스트 케이스를 만들어 줍니다
poem.txt
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.

How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!

텍스트를 채워 넣었다면 예제 11-4처럼 src/main.rs에 파일을 읽는 코드를 추가하세요.

HTML 다이어그램: /docs/rust/ch11/ch11-2/1.html
예제 11-4: 두 번째 인수로 명시된 파일의 내용물 읽기
src/main.rs
use std::env;
use std::fs;

fn main() {
    // --생략--
    println!("In file {}", file_path);

    let contents = fs::read_to_string(file_path)
        .expect("Should have been able to read the file");

    println!("With text:\n{contents}");
}

먼저 use 구문을 사용하여 표준 라이브러리의 연관된 부분을 가져옵니다.

HTML 다이어그램: /docs/rust/ch11/ch11-2/2.html

파일을 다루기 위해서는 std::fs가 필요하죠.

main에서 새로운 구문 fs::read_to_stringfile_path를 받아서 그 파일을 열고, 파일 내용물의 std::io::Result<String>을 반환합니다.

그다음 다시 한번 임시로 println! 구문을 추가하여 파일을 읽은 후 contents의 값을 출력하는 것으로 현재까지의 프로그램이 잘 작동하는지 확인합니다.

지금까지의 흐름은 파일 경로를 받아 문자열을 얻고, 잠시 expect와 출력으로 결과를 확인하는 데 초점이 있습니다.

다만 바로 다음 단계에서는 이 흐름을 관심사별로 나누고, 실패했을 때의 처리를 더 차분하게 다듬어야 합니다.

HTML 다이어그램: /docs/rust/ch11/ch11-2/3.html

첫 번째 커맨드 라인 인수에는 아무 문자열이나 넣고(아직 검색 부분은 구현하지 않았으므로) 두 번째 인수에는 poem.txt 파일을 넣어서 이 코드를 실행해봅시다.

$ cargo run -- the poem.txt
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished dev [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep the poem.txt`
Searching for the
In file poem.txt
With text.
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.

How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!

훌륭해요!

코드가 파일의 내용물을 읽은 뒤 출력했습니다.

하지만 이 코드에는 몇 가지 결점이 있습니다.

현재 main 함수에는 여러 가지 기능이 있습니다.

일반적으로 함수 하나당 단 하나의 아이디어에 대한 기능을 구현할 때 함수가 더 명료해지고 관리하기 쉬워집니다.

또 한 가지 문제는 처리 가능한 수준의 에러 처리를 안 하고 있다는 점입니다.

프로그램은 아직 작고, 따라서 이러한 결점이 큰 문제는 아니지만, 프로그램이 커지면 이 문제들을 깔끔하게 고치기 어려워질 것입니다.

작은 양의 코드를 리팩터링하는 것이 훨씬 쉽기 때문에, 프로그램을 개발할 때 일찍 리팩터링하는 것은 좋은 관행입니다.

이걸 바로 다음에 하겠습니다.

아래 다이어그램은 파일 읽기 단계가 성공한 뒤에도 남아 있는 책임 분리와 오류 처리 문제를 다음 리팩터링 항목으로 정리한 것입니다.

HTML 다이어그램: /docs/rust/ch11/ch11-2/4.html

파일 읽기 오류 처리 경로

파일 읽기 코드는 경로 입력, 열기 실패, 읽기 실패, 문자열 변환을 나누어 다뤄야 원인 메시지가 분명해집니다.

HTML 다이어그램: /docs/rust/ch11/ch11-2/7.html

파일 읽기 학습 판단 기준표

파일 읽기 마지막 점검은 실제 호출 모양과 실패 처리 경계가 자연스럽게 이어지는지에 맞춥니다.