小编典典

在 Rust 1.x 中读取和写入文件的实际方式是什么?

all

由于 Rust 相对较新,我见过太多读写文件的方法。许多是某人为他们的博客提出的非常混乱的片段,我发现的 99% 的示例都来自不再工作的不稳定构建。现在 Rust 已经稳定了,什么是用于读取或写入文件的简单、可读、不惊慌的代码片段?

这是我在读取文本文件方面最接近的东西,但即使我相当确定我已经包含了我应该拥有的所有内容,它仍然没有编译。这是基于我在所有地方的 Google+
上找到的一个片段,我唯一改变的是旧BufferedReader的现在只是BufReader

use std::fs::File;
use std::io::BufReader;
use std::path::Path;

fn main() {
    let path = Path::new("./textfile");
    let mut file = BufReader::new(File::open(&path));
    for line in file.lines() {
        println!("{}", line);
    }
}

编译器抱怨:

error: the trait bound `std::result::Result<std::fs::File, std::io::Error>: std::io::Read` is not satisfied [--explain E0277]
 --> src/main.rs:7:20
  |>
7 |>     let mut file = BufReader::new(File::open(&path));
  |>                    ^^^^^^^^^^^^^^
note: required by `std::io::BufReader::new`

error: no method named `lines` found for type `std::io::BufReader<std::result::Result<std::fs::File, std::io::Error>>` in the current scope
 --> src/main.rs:8:22
  |>
8 |>     for line in file.lines() {
  |>                      ^^^^^

总而言之,我正在寻找的是:

  • brevity
  • readability
  • covers all possible errors
  • doesn’t panic

阅读 62

收藏
2022-06-10

共1个答案

小编典典

我在这里展示的所有功能都不会自行恐慌,但我正在使用它,expect因为我不知道哪种错误处理最适合您的应用程序。去阅读 The Rust
Programming Language
错误处理章节,了解如何在你自己的程序中适当地处理失败。

Rust 1.26 及更高版本

如果您不想关心底层细节,则可以使用一行代码进行读写。

将文件读取到String

use std::fs;

fn main() {
    let data = fs::read_to_string("/etc/hosts").expect("Unable to read file");
    println!("{}", data);
}

读取文件作为Vec<u8>

use std::fs;

fn main() {
    let data = fs::read("/etc/hosts").expect("Unable to read file");
    println!("{}", data.len());
}

写一个文件

use std::fs;

fn main() {
    let data = "Some data!";
    fs::write("/tmp/foo", data).expect("Unable to write file");
}

Rust 1.0 及更高版本

String这些形式比为您分配 a或为您的单行函数稍微冗长Vec,但更强大的是您可以重用分配的数据或附加到现有对象。

读取数据

读取文件需要两个核心部分:FileRead.

将文件读取到String

use std::fs::File;
use std::io::Read;

fn main() {
    let mut data = String::new();
    let mut f = File::open("/etc/hosts").expect("Unable to open file");
    f.read_to_string(&mut data).expect("Unable to read string");
    println!("{}", data);
}

读取文件作为Vec<u8>

use std::fs::File;
use std::io::Read;

fn main() {
    let mut data = Vec::new();
    let mut f = File::open("/etc/hosts").expect("Unable to open file");
    f.read_to_end(&mut data).expect("Unable to read data");
    println!("{}", data.len());
}

写一个文件

写一个文件是类似的,除了我们使用Writetrait
并且我们总是写出字节。您可以使用以下命令将String/转换&str为字节as_bytes

use std::fs::File;
use std::io::Write;

fn main() {
    let data = "Some data!";
    let mut f = File::create("/tmp/foo").expect("Unable to create file");
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

缓冲 I/O

我觉得社区有点推动使用BufReaderBufWriter不是直接从文件中读取

缓冲读取器(或写入器)使用缓冲区来减少 I/O 请求的数量。例如,访问磁盘一次以读取 256 字节比访问磁盘 256 次效率更高。

话虽如此,我不相信缓冲读取器/写入器在读取整个文件时会有用。read_to_end似乎以较大的块复制数据,因此传输可能已经自然地合并为更少的
I/O 请求。

这是使用它进行阅读的示例:

use std::fs::File;
use std::io::{BufReader, Read};

fn main() {
    let mut data = String::new();
    let f = File::open("/etc/hosts").expect("Unable to open file");
    let mut br = BufReader::new(f);
    br.read_to_string(&mut data).expect("Unable to read string");
    println!("{}", data);
}

对于写作:

use std::fs::File;
use std::io::{BufWriter, Write};

fn main() {
    let data = "Some data!";
    let f = File::create("/tmp/foo").expect("Unable to create file");
    let mut f = BufWriter::new(f);
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

BufReader当您想逐行阅读时,A更有用:

use std::fs::File;
use std::io::{BufRead, BufReader};

fn main() {
    let f = File::open("/etc/hosts").expect("Unable to open file");
    let f = BufReader::new(f);

    for line in f.lines() {
        let line = line.expect("Unable to read line");
        println!("Line: {}", line);
    }
}
2022-06-10