Rust相对较新,我见过太多读取和写入文件的方法。许多都是一些人为他们的博客写的极其混乱的代码片段,我发现99%的例子(甚至在Stack Overflow上)都来自不稳定的构建,不再工作。现在Rust已经稳定了,那么用于读取或写入文件的简单、可读、不恐慌的代码片段是什么呢?

这是我所得到的最接近于读取文本文件的东西,但它仍然没有编译,即使我相当确定我已经包含了我应该包含的所有内容。这是基于我在谷歌+的所有地方发现的一个片段,我唯一改变的是,旧的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() {
  |>                      ^^^^^

综上所述,我所寻求的是:

简洁 可读性 涵盖所有可能的错误 不恐慌


当前回答

对于任何写入文件的人来说,接受的答案是很好的,但如果你需要追加到文件中,你必须使用OpenOptions结构体:

use std::io::Write;
use std::fs::OpenOptions;

fn main() {
    let data = "Some data!\n";
    let mut f = OpenOptions::new()
        .append(true)
        .create(true) // Optionally create the file if it doesn't already exist
        .open("/tmp/foo")
        .expect("Unable to open file");
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

缓冲写入仍然以相同的方式工作:

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

fn main() {
    let data = "Some data!\n";
    let f = OpenOptions::new()
        .append(true)
        .open("/tmp/foo")
        .expect("Unable to open file");
    let mut f = BufWriter::new(f);
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

其他回答

对于任何写入文件的人来说,接受的答案是很好的,但如果你需要追加到文件中,你必须使用OpenOptions结构体:

use std::io::Write;
use std::fs::OpenOptions;

fn main() {
    let data = "Some data!\n";
    let mut f = OpenOptions::new()
        .append(true)
        .create(true) // Optionally create the file if it doesn't already exist
        .open("/tmp/foo")
        .expect("Unable to open file");
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

缓冲写入仍然以相同的方式工作:

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

fn main() {
    let data = "Some data!\n";
    let f = OpenOptions::new()
        .append(true)
        .open("/tmp/foo")
        .expect("Unable to open file");
    let mut f = BufWriter::new(f);
    f.write_all(data.as_bytes()).expect("Unable to write data");
}

我在这里展示的函数本身都不恐慌,但我使用expect,因为我不知道哪种错误处理最适合您的应用程序。去阅读Rust编程语言关于错误处理的章节,了解如何在自己的程序中适当地处理失败。

Rust 1.26及以上版本

如果不想关心底层细节,可以使用一行函数进行读写。

将文件读入字符串

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或Vec的单行函数稍微详细一些,但更强大的地方在于您可以重用分配的数据或附加到现有对象。

读取数据

读取文件需要两个核心部分:文件和读取。

将文件读入字符串

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());
}

写入文件

写入文件与此类似,只不过我们使用了Write特性,并且总是写入字节。你可以使用as_bytes将String / &str转换为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

我感觉社区在推动我使用buffreader和buffwriter,而不是直接从文件中读取

缓冲读取器(或写入器)使用缓冲区来减少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");
}

当你想逐行读取时,buffreader更有用:

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);
    }
}

通过使用缓冲I/O,您可以复制的文件大小大于实际内存。


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

fn main() {
    let read = File::open(r#"E:\1.xls"#);

    let write = OpenOptions::new().write(true).create(true).open(r#"E:\2.xls"#);

    let mut reader = BufReader::new(read.unwrap());

    let mut writer = BufWriter::new(write.unwrap());

    let mut length = 1;

    while length > 0 {
        let buffer = reader.fill_buf().unwrap();

        writer.write(buffer);

        length = buffer.len();
        reader.consume(length);
    }
}