读取文件
Reading a File
现在我们将添加读取 file_path 参数中指定的文件功能。首先,我们需要一个示例文件来进行测试:我们将使用一个包含少量多行文本且带有一些重复单词的文件。示例 12-3 中的艾米莉·狄金森(Emily Dickinson)的诗非常适合!在项目的根目录下创建一个名为 poem.txt 的文件,并输入这首诗 “I’m Nobody! Who are you?”
Now we’ll add functionality to read the file specified in the file_path
argument. First, we need a sample file to test it with: We’ll use a file with a
small amount of text over multiple lines with some repeated words. Listing 12-3
has an Emily Dickinson poem that will work well! Create a file called
poem.txt at the root level of your project, and enter the poem “I’m Nobody!
Who are you?”
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!
文本准备就绪后,编辑 src/main.rs 并添加读取文件的代码,如示例 12-4 所示。
With the text in place, edit src/main.rs and add code to read the file, as shown in Listing 12-4.
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}");
}
首先,我们通过 use 语句引入标准库的相关部分:我们需要 std::fs 来处理文件。
First, we bring in a relevant part of the standard library with a use
statement: We need std::fs to handle files.
在 main 函数中,新增的语句 fs::read_to_string 接收 file_path,打开该文件,并返回一个包含文件内容的 std::io::Result<String> 类型的值。
In main, the new statement fs::read_to_string takes the file_path, opens
that file, and returns a value of type std::io::Result<String> that contains
the file’s contents.
之后,我们再次添加一个临时的 println! 语句,在文件读取后打印 contents 的值,以便检查程序目前是否正常工作。
After that, we again add a temporary println! statement that prints the value
of contents after the file is read so that we can check that the program is
working so far.
让我们运行这段代码,使用任意字符串作为第一个命令行参数(因为我们还没有实现搜索部分),并将 poem.txt 文件作为第二个参数:
Let’s run this code with any string as the first command line argument (because we haven’t implemented the searching part yet) and the poem.txt file as the second argument:
$ 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 函数承担了多项职责:通常情况下,如果每个函数只负责一个功能,函数会更清晰且更易于维护。另一个问题是,我们处理错误的方式还不够完善。虽然程序目前还很小,这些缺陷不是大问题,但随着程序的增长,以干净的方式修复它们将变得更加困难。在开发程序时尽早开始重构是一个良好的实践,因为重构少量的代码要容易得多。我们接下来的工作就是重构。
Great! The code read and then printed the contents of the file. But the code
has a few flaws. At the moment, the main function has multiple
responsibilities: Generally, functions are clearer and easier to maintain if
each function is responsible for only one idea. The other problem is that we’re
not handling errors as well as we could. The program is still small, so these
flaws aren’t a big problem, but as the program grows, it will be harder to fix
them cleanly. It’s a good practice to begin refactoring early on when
developing a program because it’s much easier to refactor smaller amounts of
code. We’ll do that next.