在 Rust 1.x 中读写文件的实际方式是什么? [英] What's the de-facto way of reading and writing files in Rust 1.x?

查看:20
本文介绍了在 Rust 1.x 中读写文件的实际方式是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于 Rust 相对较新,我见过太多读写文件的方法.许多是某人为他们的博客提出的极其混乱的片段,我发现的 99% 的示例(甚至在 Stack Overflow 上)都来自不再有效的不稳定构建.既然 Rust 已经稳定了,那么什么是用于读取或写入文件的简单、可读、无恐慌的代码段?

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

使用 std::fs::File;使用 std::io::BufReader;使用 std::path::Path;fn 主(){let path = Path::new("./textfile");让 mut file = BufReader::new(File::open(&path));对于 file.lines() 中的行 {println!("{}", line);}}

编译器抱怨:

错误:特征绑定`std::result::Result<std::fs::File, std::io::Error>: std::io::Read` 不满足 [--explain E0277]-->src/main.rs:7:20|>7 |>让 mut file = BufReader::new(File::open(&path));|>^^^^^^^^^^^^^^^注意:`std::io::BufReader::new` 需要错误:在当前类型中没有找到名为 `lines` 的方法,用于类型 `std::io::BufReader>`范围-->src/main.rs:8:22|>8 |>对于 file.lines() 中的行 {|>^^^^^

总结一下,我要找的是:

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

解决方案

我这里展示的函数都没有自己恐慌,但我使用的是 expect 因为我不知道是什么样的错误处理将最适合您的应用程序.去阅读Rust 编程语言关于错误处理的章节,以了解如何在您自己的程序中适当地处理失败.

Rust 1.26 及更高版本

如果你不想关心底层的细节,有读写的单行函数.

读取文件到String

使用 std::fs;fn 主(){let data = fs::read_to_string("/etc/hosts").expect("无法读取文件");println!("{}", 数据);}

读取文件作为Vec

使用 std::fs;fn 主(){let data = fs::read("/etc/hosts").expect("无法读取文件");println!("{}", data.len());}

写入文件

使用 std::fs;fn 主(){let data = "一些数据!";fs::write("/tmp/foo", data).expect("无法写入文件");}

Rust 1.0 及更高版本

这些形式比为您分配 StringVec 的单行函数稍微冗长一些,但功能更强大,因为您可以重用分配的数据或附加到现有对象.

读取数据

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

读取文件到String

使用 std::fs::File;使用 std::io::Read;fn 主(){让 mut data = String::new();let mut f = File::open("/etc/hosts").expect("无法打开文件");f.read_to_string(&mut data).expect("无法读取字符串");println!("{}", 数据);}

读取文件作为Vec

使用 std::fs::File;使用 std::io::Read;fn 主(){让 mut 数据 = Vec::new();let mut f = File::open("/etc/hosts").expect("无法打开文件");f.read_to_end(&mut data).expect("无法读取数据");println!("{}", data.len());}

写入文件

写文件类似,除了我们使用Write trait,我们总是写出字节.您可以使用 as_bytes:

使用 std::fs::File;使用 std::io::Write;fn 主(){let data = "一些数据!";let mut f = File::create("/tmp/foo").expect("无法创建文件");f.write_all(data.as_bytes()).expect("无法写入数据");}

缓冲 I/O

<块引用>

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

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

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

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

使用 std::fs::File;使用 std::io::{BufReader, Read};fn 主(){让 mut data = String::new();let f = File::open("/etc/hosts").expect("无法打开文件");让 mut br = BufReader::new(f);br.read_to_string(&mut data).expect("无法读取字符串");println!("{}", 数据);}

对于写作:

使用 std::fs::File;使用 std::io::{BufWriter, Write};fn 主(){let data = "一些数据!";let f = File::create("/tmp/foo").expect("无法创建文件");让 mut f = BufWriter::new(f);f.write_all(data.as_bytes()).expect("无法写入数据");}

BufReader 在你想逐行阅读时更有用:

使用 std::fs::File;使用 std::io::{BufRead, BufReader};fn 主(){let f = File::open("/etc/hosts").expect("无法打开文件");让 f = BufReader::new(f);对于 f.lines() { 中的行let line = line.expect("无法读取行");println!("行:{}",行);}}

With Rust being comparatively new, I've seen far too many ways of reading and writing files. Many are extremely messy snippets someone came up with for their blog, and 99% of the examples I've found (even on Stack Overflow) are from unstable builds that no longer work. Now that Rust is stable, what is a simple, readable, non-panicking snippet for reading or writing files?

This is the closest I've gotten to something that works in terms of reading a text file, but it's still not compiling even though I'm fairly certain I've included everything I should have. This is based off of a snippet I found on Google+ of all places, and the only thing I've changed is that the old BufferedReader is now just 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);
    }
}

The compiler complains:

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() {
  |>                      ^^^^^

To sum it up, what I'm looking for is:

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

解决方案

None of the functions I show here panic on their own, but I am using expect because I don't know what kind of error handling will fit best into your application. Go read The Rust Programming Language's chapter on error handling to understand how to appropriately handle failure in your own program.

Rust 1.26 and onwards

If you don't want to care about the underlying details, there are one-line functions for reading and writing.

Read a file to a String

use std::fs;

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

Read a file as a Vec<u8>

use std::fs;

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

Write a file

use std::fs;

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

Rust 1.0 and onwards

These forms are slightly more verbose than the one-line functions that allocate a String or Vec for you, but are more powerful in that you can reuse allocated data or append to an existing object.

Reading data

Reading a file requires two core pieces: File and Read.

Read a file to a 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);
}

Read a file as a 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 a file

Writing a file is similar, except we use the Write trait and we always write out bytes. You can convert a String / &str to bytes with 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");
}

Buffered I/O

I felt a bit of a push from the community to use BufReader and BufWriter instead of reading straight from a file

A buffered reader (or writer) uses a buffer to reduce the number of I/O requests. For example, it's much more efficient to access the disk once to read 256 bytes instead of accessing the disk 256 times.

That being said, I don't believe a buffered reader/writer will be useful when reading the entire file. read_to_end seems to copy data in somewhat large chunks, so the transfer may already be naturally coalesced into fewer I/O requests.

Here's an example of using it for reading:

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

And for writing:

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

A BufReader is more useful when you want to read line-by-line:

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

这篇关于在 Rust 1.x 中读写文件的实际方式是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆