第11.1章: 文件 I/O
概述
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章)中介绍。
要点
- 读用
ibuf_file,写用obuf_file,两者都用用iobuf_file。 - 每种类型有五个字符变体:
char、u8(char8_t)、u16(char16_t)、u32(char32_t)以及w(wchar_t)。 - 文件由 RAII 管理 — 离开作用域时自动关闭。
- 用
open_mode标志控制打开行为。没有open_mode::binary— 原生文件永远是二进制模式。open_mode::text在 DOS/Windows(不含 Cygwin)上启用 CRLF 与 LF 的转换;在纯 POSIX 上它被忽略,但在 Windows 上可能被 POSIX 层兑现。 - 先
using namespace ::fast_io::iomnp;(它包含::fast_io::io),然后就能直接调用println/print/scan,以及像str_line_get这样的操纵器。 - 逐行读取时使用
scan搭配str_line_get操纵器:for (::fast_io::string line; scan<true>(ibf, str_line_get(line)); ) { ... } - 你不能在不同字符类型之间直接打印。用
::fast_io::mnp::code_cvt转换,或者写到字符类型匹配的设备上。 - 用
::fast_io::dir_file打开目录,再用at(df)相对于它打开文件。目录遍历见第11.18章。