## 读取文件

> ch12-02-reading-a-file.md
> commit 02a168ed346042f07010f8b65b4eeed623dd31d1

现在我们要增加读取由 `file_path` 命令行参数指定的文件的功能。首先，需要一个用来测试的示例文件：我们会用一个拥有多行少量文本且有一些重复单词的文件。示例 12-3 是一首艾米莉·狄金森（Emily Dickinson）的诗，它正适合这个工作！在项目根目录创建一个文件 `poem.txt`，并输入诗 "I'm nobody! Who are you?"：

文件名：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!

示例 12-3：艾米莉·狄金森的诗 “I’m nobody! Who are you?”，一个好的测试用例

创建完这个文件之后，修改 src/main.rs 并增加如示例 12-4 所示的打开文件的代码：

文件名：src/main.rs

    use std::env;
    use std::fs;

    fn main() {
        // --snip--
        let args: Vec<String> = env::args().collect();

        let query = &args[1];
        let file_path = &args[2];

        println!("Searching for {query}");
        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}");
    }

示例 12-4：读取第二个参数所指定的文件内容

首先，我们增加了一个 `use` 语句来引入标准库中的相关部分：我们需要 `std::fs` 来处理文件。

在 `main` 中新增了一行语句：`fs::read_to_string` 接受 `file_path`，打开文件，接着返回包含其内容的 `std::io::Result<String>`。

在这些代码之后，我们再次增加了临时的 `println!` 打印出读取文件之后 `contents` 的值，这样就可以检查目前为止的程序能否工作。

尝试运行这些代码，随意指定一个字符串作为第一个命令行参数（因为还未实现搜索功能的部分）而将 poem.txt 文件将作为第二个参数：

    $ cargo run -- the poem.txt
       Compiling minigrep v0.1.0 (file:///projects/minigrep)
        Finished `dev` profile [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` 函数有着多个职能，通常函数只负责一个功能的话会更简洁并易于维护。另一个问题是没有尽可能的处理错误。虽然我们的程序还很小，这些瑕疵并不是什么大问题，不过随着程序功能的丰富，将会越来越难以用简单的方法修复它们。在开发程序时，及早开始重构是一个最佳实践，因为重构少量代码时要容易的多，所以让我们现在就开始吧。