键盘快捷键

按 ← 或 → 在章节之间导航

按 S 或 / 在本书中搜索

按 ? 显示此帮助

按 Esc 隐藏此帮助

读取文件

现在我们将添加功能来读取 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:艾米莉·狄金森的一首诗,是一个很好的测试用例。

有了文本之后,编辑 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 函数承担了多个职责:通常来说,如果每个函数只负责一个想法,函数会更清晰、更易于维护。另一个问题是我们没有尽可能好地处理错误。程序还很小,所以这些缺陷不是大问题,但随着程序的增长,要干净利落地修复它们会更难。在开发程序时尽早开始重构是一个好做法,因为重构较小的代码量要容易得多。我们接下来就会这样做。