展开描述
异步文件实用工具。
本模块包含用于以异步方式处理文件系统的实用方法。 包括对文件的读/写,以及对目录的操作。
请注意,大多数操作系统并不提供异步文件系统 API。
因此,Tokio 在内部会使用普通的阻塞文件操作。
这是通过 spawn_blocking 线程池在后台运行它们来完成的。
tokio::fs 模块仅应用于普通文件。
在 Linux 上试图将其用于命名管道等特殊文件
可能会导致意外行为,例如在运行时关闭期间挂起。
对于特殊文件,应改用 tokio::net::unix::pipe 或 AsyncFd 等专用类型。
当前,Tokio 在所有平台上都会使用 spawn_blocking,
但将来可能会改为使用异步文件系统 API(如 io_uring)。
§Usage
使用此模块的最简单方法是使用对整个文件进行操作的实用函数:
这两个 read 函数读取整个文件并返回其内容。
write 函数获取文件的内容并将这些内容
写入文件。如果文件已存在,则覆盖它。
例如,要读取文件:
let contents = tokio::fs::read_to_string("my_file.txt").await?;
println!("File has {} lines.", contents.lines().count());若要覆盖该文件:
let contents = "First line.\nSecond line.\nThird line.\n";
tokio::fs::write("my_file.txt", contents.as_bytes()).await?;§Using File
与文件交互的主要类型是 File。它可用于
读取和写入给定文件。
这是通过 AsyncRead 和
AsyncWrite trait 完成的。当你想做
一些比一次性读取或写入整个内容
更复杂的操作时,通常会使用此类型。
注意:在使用 Tokio 的 File
写入时,使用 flush 非常重要。
这是因为对 write 的调用会在写入完成之前返回,
而 flush 会等待写入完成。
(即使你不调用 flush,写入也会发生;
只是会稍后发生。)这与 std::fs::File 不同,
原因是 File 在内部使用了 spawn_blocking。
例如,若要统计文件中的行数,而又不将整个文件加载到内存中:
use tokio::fs::File;
use tokio::io::AsyncReadExt;
let mut file = File::open("my_file.txt").await?;
let mut chunk = vec![0; 4096];
let mut number_of_lines = 0;
loop {
let len = file.read(&mut chunk).await?;
if len == 0 {
// Length of zero means end of file.
break;
}
for &b in &chunk[..len] {
if b == b'\n' {
number_of_lines += 1;
}
}
}
println!("File has {} lines.", number_of_lines);例如,要逐行写入文件:
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
let mut file = File::create("my_file.txt").await?;
file.write_all(b"First line.\n").await?;
file.write_all(b"Second line.\n").await?;
file.write_all(b"Third line.\n").await?;
// Remember to call `flush` after writing!
file.flush().await?;§调优你的文件 IO
Tokio 的文件在内部使用 spawn_blocking,
这会产生严重的性能影响。
为了在 Tokio 上获得良好的文件 IO 性能,
建议将操作批量到尽可能少的 spawn_blocking 调用中。
这种差异的一个例子可以通过比较上面的两个读取示例看出。
第一个示例使用 tokio::fs::read,
它在一次 spawn_blocking 调用中读取整个文件,
然后返回。
第二个示例将使用许多 spawn_blocking 调用以块的方式读取文件。
这意味着对于大文件,第二个示例很可能更昂贵。
(当然,对于不适合放在内存中的超大文件,使用块读取可能是必要的。)
下面的示例将展示一些针对此的策略:
创建文件时,将数据写入 String 或 Vec<u8>,
然后通过 tokio::fs::write
在一次 spawn_blocking 调用中写入整个文件。
let mut contents = String::new();
contents.push_str("First line.\n");
contents.push_str("Second line.\n");
contents.push_str("Third line.\n");
tokio::fs::write("my_file.txt", contents.as_bytes()).await?;使用 BufReader 和 BufWriter
将许多小的读或写缓冲为几个大的。此示例
很可能只会执行一次 spawn_blocking 调用。
use tokio::fs::File;
use tokio::io::{AsyncWriteExt, BufWriter};
let mut file = BufWriter::new(File::create("my_file.txt").await?);
file.write_all(b"First line.\n").await?;
file.write_all(b"Second line.\n").await?;
file.write_all(b"Third line.\n").await?;
// Due to the BufWriter, the actual write and spawn_blocking
// call happens when you flush.
file.flush().await?;在 spawn_blocking 中手动使用 std::fs。
use std::fs::File;
use std::io::{self, Write};
use tokio::task::spawn_blocking;
spawn_blocking(move || {
let mut file = File::create("my_file.txt")?;
file.write_all(b"First line.\n")?;
file.write_all(b"Second line.\n")?;
file.write_all(b"Third line.\n")?;
// Unlike Tokio's file, the std::fs file does
// not need flush.
io::Result::Ok(())
}).await.unwrap()?;最好也注意 File::set_max_buf_size,
它控制 Tokio 的 File
在单次 spawn_blocking 调用中
读取或写入的最大字节数。默认为 2 MB,
但这可能会更改。
结构体§
- DirBuilder
- 用于以各种方式创建目录的构建器。
- DirEntry
ReadDir流所返回的条目。- File
- 对文件系统上已打开文件的引用。
- Open
Options - 可用于配置文件打开方式的选项和标志。
- ReadDir
- 读取目录中的条目。
函数§
- canonicalize
- 返回路径的规范化绝对形式, 其中所有中间组件都被归一化, 符号链接也被解析。
- copy
- 将一个文件的内容复制到另一个文件。 此函数还会将 原始文件的权限位 复制到目标文件。 此函数将覆盖目标的内容。
- create_
dir - 在所提供的路径处 创建一个新的空目录。
- create_
dir_ all - 递归地创建目录 及其所有缺失的父组件。
- hard_
link - 在文件系统上 创建一个新的硬链接。
- metadata
- 给定一个路径, 查询文件系统以获取有关文件、 目录等的信息。
- read
- 将文件的全部内容 读取到字节向量中。
- read_
dir - 返回目录内条目的流。
- read_
link - 读取符号链接, 返回该链接所指向的文件。
- read_
to_ string - 创建一个 future, 该 future 将打开一个文件以供读取, 将其全部内容读取到一个字符串中, 并返回该字符串。
- remove_
dir - 移除一个现有的空目录。
- remove_
dir_ all - 在移除所有内容后 移除该路径处的目录。 请谨慎使用!
- remove_
file - 从文件系统中 移除一个文件。
- rename
- 将文件或目录重命名为新名称,
如果
to已存在, 则替换原始文件。 - set_
permissions - 更改文件或目录上的权限。
- symlink_
dir - 在文件系统上 创建一个新的目录符号链接。
- symlink_
file - 在文件系统上 创建一个新的文件符号链接。
- symlink_
metadata - 查询某路径的文件系统元数据。
- try_
exists - 如果该路径指向一个已存在的实体,
则返回
Ok(true)。 - write
- 创建一个 future,
该 future 将打开一个文件以供写入,
并将
contents的全部内容写入其中。