第11.1章: 文件 I/O

English

概述

fast_io 通过若干带缓冲的文件类型提供高性能文件 I/O。它们在原生文件句柄之上加了用户态缓冲区,以获得最大吞吐量。

1. 文件类型

每种带缓冲的文件类型都有五种字符类型变体。默认使用 char;其余分别带 u8、u16、u32 前缀,或者带 w 前缀(表示 wchar_t)。

方向 char char8_t char16_t char32_t wchar_t
输入 ibuf_file u8ibuf_file u16ibuf_file u32ibuf_file wibuf_file
输出 obuf_file u8obuf_file u16obuf_file u32obuf_file wobuf_file
输入/输出 iobuf_file u8iobuf_file u16iobuf_file u32iobuf_file wiobuf_file

所有文件类型都由 RAII 管理:对象离开作用域时文件会自动关闭。

2. Hello World 示例

这里是一个完整的文件 I/O 示例:


#include <fast_io.h>
#include <fast_io_device.h>

int main() {
    using namespace ::fast_io::iomnp;

    // Write to a file
    {
        ::fast_io::obuf_file obf(u8"hello.txt");
        print(obf, "Hello, File I/O!\n"
                   "Line 2: ", 42, " + ", 100, " = ", 142);
    } // file closed automatically here

    // Read from the file line by line
    {
        ::fast_io::ibuf_file ibf(u8"hello.txt");
        for (::fast_io::string line; scan<true>(ibf, str_line_get(line)); ) {
            println(line);
        }
    }
}

3. 打开模式

用 ::fast_io::open_mode 控制文件如何打开。最常用的跨平台标志有:

标志 说明
open_mode::in 以读方式打开。
open_mode::out 以写方式打开。
open_mode::app 追加模式(写入落到末尾)。
open_mode::trunc 把已有文件截断为零长度。
open_mode::creat 文件不存在时创建它。
open_mode::excl 文件已存在则失败(也叫 noreplace)。
open_mode::direct 绕过操作系统页缓存(POSIX 的 O_DIRECT)。
open_mode::sync 同步 I/O — 每次写入后刷新。
open_mode::no_block 非阻塞模式。
open_mode::text 文本模式(换行转换)。在 DOS/Windows 上(不含 Cygwin),这会启用 CRLF 与 LF 之间的转换。在纯 POSIX 系统上被 native_file 忽略,但在 Windows 上可能被 POSIX 层兑现。只对 c_file 与 filebuf_file 有意义。
open_mode::temporary 创建一个关闭时即被删除的临时文件。

此外还有针对 Windows 属性的平台专用标志(例如 hidden、archive、compressed、encrypted),以及 Linux 专用标志(例如 no_atime、path)。

用 | 组合标志:


// Open for writing, create if not exists, truncate if exists
::fast_io::obuf_file obf(u8"data.bin", ::fast_io::open_mode::out | ::fast_io::open_mode::trunc);

// Open for reading and writing
::fast_io::iobuf_file iof(u8"data.txt", ::fast_io::open_mode::in | ::fast_io::open_mode::out);

4. UTF-8 文件 I/O

对 UTF-8 文本文件,使用 u8 变体。注意 u8string 使用 char8_t,它与标准输出所用的 char 是不同的字符类型。要把 UTF-8 文本打印到控制台,可以用包住 stdout 的 u8obuf_file,或者用 ::fast_io::mnp::code_cvt 在字符类型之间转换。


#include <fast_io.h>
#include <fast_io_device.h>
#include <fast_io_legacy.h>

int main() {
    using namespace ::fast_io::iomnp;

    // Write UTF-8 to a file
    {
        ::fast_io::u8obuf_file u8obf("utf8.txt");
        print(u8obf, u8"Unicode: 你好世界 🌍\n");
    }

    // Read UTF-8 file and print to a UTF-8 stdout
    {
        ::fast_io::u8ibuf_file u8ibf("utf8.txt");
        ::fast_io::u8c_io_observer u8out(stdout);
        for (::fast_io::u8string line; scan<true>(u8ibf, str_line_get(line)); ) {
            println(u8out, line);
        }
    }
}

5. 相对于某个目录打开文件

::fast_io::dir_file 打开一个目录句柄。用 at(df) 相对于该目录打开文件 — 这比拼接完整路径更安全、更高效,也避免了路径解析带来的竞态。


#include <fast_io.h>
#include <fast_io_device.h>

int main() {
    using namespace ::fast_io::iomnp;

    // Open a directory
    ::fast_io::dir_file df(u8"my_directory");

    // Open a file relative to that directory
    ::fast_io::obuf_file obf(at(df), "hello.txt");
    print(obf, "Written relative to my_directory\n");
}

完整的目录遍历 API(current(at(df))、recursive(at(df)) 以及目录项相关函数)在文件系统一章(第11.18章)中介绍。

要点