파일 읽기
명령줄에서 받은 경로의 텍스트 파일을 읽어 출력하고 존재하지 않거나 읽을 수 없는 파일의 실패 경로를 확인합니다.
이제는 file_path 인수에 명시된 파일을 읽는 기능을 추가해보겠습니다.
우선 테스트에 사용할 샘플 파일이 필요합니다.
여러 줄의 몇 개의 반복된 단어들로 구성된 작은 양의 텍스트로 된 파일을 사용하겠습니다.
예제 11-3은 딱 맞게 사용될 에밀리 딕킨슨(Emily Dickinson)의 시가 있습니다!
프로젝트의 루트 레벨에 poem.txt이라는 이름의 파일을 만들고, 시 ‘I’m Nobody! Who are you?’를 입력하세요.
예제 11-3: 에밀리 딕킨슨의 시는 좋은 테스트 케이스를 만들어 줍니다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에 파일을 읽는 코드를 추가하세요.
FLOWCHART · I/O RESULT
파일 경로에서 UTF-8 문자열까지의 Result 경계
fs::read_to_string은 경로를 열고 파일 전체를 읽어 유효한 UTF-8 String을 만든다. 열기·읽기·디코딩 중 어느 단계가 실패해도 하나의 io::Result<String> 경계로 돌아온다.
- 입력 경로
file_path는 실제 열기 동작의 입력이다. 별도의 사전 경로 검사가 오류를 없애 주지는 않습니다. - 전체 텍스트 읽기
fs::read_to_string은 파일 전체를 새String으로 읽으므로 메모리 사용량은 파일 크기에 따라 늘어납니다. - 강한 UTF-8 계약
경로가 없거나 열기·읽기가 실패하거나 바이트가 유효한 UTF-8이 아니면
Err입니다. 임의 바이트는fs::read를 사용합니다. - 성공 경로
Ok(String)은 검색과 출력 같은 다음 처리로 전달됩니다. - 오류 정책
초기
expect는 문맥과 함께 패닉하는 교육 단계다. 리팩터링 뒤에는Result를 호출자에게 전파해 정책을 분리합니다.
운영체제별 오류 종류와 메시지는 고정하지 않는다. 이 도식의 안정적인 계약은 전체 UTF-8 텍스트 또는 io::Error라는 결과 경계다.
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 구문을 사용하여 표준 라이브러리의 연관된 부분을 가져옵니다.
파일을 다루기 위해서는 std::fs가 필요하죠.
main에서 새로운 구문 fs::read_to_string이 file_path를 받아서 그
파일을 열고, 파일 내용물의 std::io::Result<String>을 반환합니다.
그다음 다시 한번 임시로 println! 구문을 추가하여 파일을 읽은 후
contents의 값을 출력하는 것으로 현재까지의 프로그램이 잘 작동하는지
확인합니다.
지금까지의 흐름은 파일 경로를 받아 문자열을 얻고, 잠시 expect와 출력으로 결과를 확인하는 데 초점이 있습니다.
다만 바로 다음 단계에서는 이 흐름을 관심사별로 나누고, 실패했을 때의 처리를 더 차분하게 다듬어야 합니다.
첫 번째 커맨드 라인 인수에는 아무 문자열이나 넣고(아직 검색 부분은 구현하지 않았으므로) 두 번째 인수에는 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 함수에는 여러 가지 기능이 있습니다.
일반적으로 함수 하나당 단 하나의 아이디어에 대한 기능을 구현할 때 함수가 더 명료해지고 관리하기 쉬워집니다.
또 한 가지 문제는 처리 가능한 수준의 에러 처리를 안 하고 있다는 점입니다.
프로그램은 아직 작고, 따라서 이러한 결점이 큰 문제는 아니지만, 프로그램이 커지면 이 문제들을 깔끔하게 고치기 어려워질 것입니다.
작은 양의 코드를 리팩터링하는 것이 훨씬 쉽기 때문에, 프로그램을 개발할 때 일찍 리팩터링하는 것은 좋은 관행입니다.
이걸 바로 다음에 하겠습니다.
파일 읽기 오류 처리 경로
파일 읽기 코드는 경로 입력, 열기 실패, 읽기 실패, 문자열 변환을 나누어 다뤄야 원인 메시지가 분명해집니다.
파일 읽기 학습 판단 기준표
파일 읽기 마지막 점검은 실제 호출 모양과 실패 처리 경계가 자연스럽게 이어지는지에 맞춥니다.