跳到主要内容

Module fs

搜索

Module fs 

Source
展开描述

异步文件实用工具。

本模块包含用于以异步方式处理文件系统的实用方法。 包括对文件的读/写,以及对目录的操作。

请注意,大多数操作系统并不提供异步文件系统 API。 因此,Tokio 在内部会使用普通的阻塞文件操作。 这是通过 spawn_blocking 线程池在后台运行它们来完成的。

tokio::fs 模块仅应用于普通文件。 在 Linux 上试图将其用于命名管道等特殊文件 可能会导致意外行为,例如在运行时关闭期间挂起。 对于特殊文件,应改用 tokio::net::unix::pipeAsyncFd 等专用类型。

当前,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。它可用于 读取和写入给定文件。 这是通过 AsyncReadAsyncWrite 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 调用以块的方式读取文件。 这意味着对于大文件,第二个示例很可能更昂贵。 (当然,对于不适合放在内存中的超大文件,使用块读取可能是必要的。)

下面的示例将展示一些针对此的策略:

创建文件时,将数据写入 StringVec<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?;

使用 BufReaderBufWriter 将许多小的读或写缓冲为几个大的。此示例 很可能只会执行一次 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
对文件系统上已打开文件的引用。
OpenOptions
可用于配置文件打开方式的选项和标志。
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 的全部内容写入其中。