读取文件

现在就要添加读取那个在 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:一首 Emily Dickinson 的诗歌成就了一个良好的测试用例

有了这个文本后,就要编辑 src/main.rs 并添加读取该文件的代码了,如下清单 12-4 中所示。

文件名:src/main.rs

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

fn main() {
    // --跳过代码--
    println! ("在文件 {} 中检索:{}", file_path, query);

    let contents = fs::read_to_string(file_path)
        .expect("应能读取这个这个文件");

    println! ("有着文本:\n{}", contents);
}

清单 12-4:对由第二个参数所指定的文件内容进行读取

首先,这里使用了一个 use 语句,将标准库的一个相对部分(a relevant part)带入进来:这里需要 std::fs 来对文件进行处理。

main 函数中,那个新的 fs::read_to_string 取了其中的 file_path 做参数,打开那个文件,并返回一个该文件内容的 std::io::Result<String> 类型值。

在那之后,这里再次添加了一个临时的、于该文件被读取之后打印 contents 值的 println! 语句,因此这里就该程序到此在运行而进行检查了。

下面就来以任意字符串作为第一个参数(由于这里尚未实现检索的部分),并以那个 poem.txt 文件作为第二个参数,运行这段代码:

#![allow(unused)]
fn main() {
$ cargo run -- the poem.txt                                                                    lennyp@vm-manjaro
   Compiling minigrep v0.1.0 (/home/lennyp/rust-lang/minigrep)
    Finished dev [unoptimized + debuginfo] target(s) in 0.36s
     Running `target/debug/minigrep the poem.txt`
在文件 poem.txt 中检索:the
有着文本:
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 函数,有着多重义务:一般来讲,在每个函数只负责一件事情时,那么他们就是些更为清晰明了,并更易于维护的函数了。另一问题则是这里没有尽可能地对错误进行处理。这个程序还很小,因此这些缺陷就不是什么大问题,不过随着程序变大,就会变得更加难于彻底修复这些缺陷。在开发某个程序时,由于重构数量较少的代码要容易得多,因此尽早开始重构,是一种良好实践。接下来就会干这件事 -- 重构。

Last change: 2023-11-30, commit: 0a57043