第26.4章:transmit

English

1. transmit 用来做什么

transmit 把字节从输入设备搬到输出设备。它不格式化、不解析、不解释这些字节。 它是核心 I/O 三件套的第三个成员:print 写值,scan 读值, transmit 搬字节流。

这个操作存在,是因为手写循环很容易在细节上出错。一次 read 可能少于你要求的字节数;一次 write 可能只接受一部分; 两者都可能被中断;带缓冲的输入设备可能已经持有一些字节, 而直接的描述符复制会越过它们。transmit 在一个地方处理所有这些情况。

2. 两个操作

操作 返回 含义
::fast_io::operations::transmit_some_bytes(out, off_out, in, off_in, size) ::std::size_t 最多搬 size 字节。返回这一轮实际搬了多少;0 表示输入结束。
::fast_io::operations::transmit_all_bytes(out, off_out, in, off_in, total) void 重复直到输入结束或可选上界耗尽。

off_out 和 off_in 是 fpos_nullable_ptr。 传 {} 表示使用并推进设备自己的位置。传一个 intfpos_t 引用表示在显式偏移处传输,不移动设备自己的位置; 被引用的值会推进到已传输字节之后。

total 是 size_t_opt。{} 表示“直到 EOF”; ::fast_io::size_t_opt{n} 表示“最多 n 字节”。 这是给已经知道 body 长度的协议用的上界。

3. 文件到文件


#include <fast_io.h>

int main()
{
    ::fast_io::ibuf_file in("input.bin");
    ::fast_io::obuf_file out("output.bin");

    ::fast_io::operations::transmit_all_bytes(out, {}, in, {}, {});
}

应用代码里没有临时缓冲区。如果平台和设备类型支持内核复制路径, transmit_all_bytes 可以使用 copy_file_range、 splice 或 sendfile;否则退回一个有界内部缓冲区。 应用不需要维护两个版本的复制。

设备不必是文件。同一个调用可以把字节从管道搬到文件、从 socket 搬到文件, 或从文件搬到 socket。这也是进程与管道那一章使用同一操作的原因: 子进程写进管道,父进程把管道 transmit 到自己的输出。

4. 有界传输

带长度前缀的协议应该把长度传进去。即使输入还有更多字节,传输也会在上界处停止:


::std::size_t const body_length{content_length};

::fast_io::operations::transmit_all_bytes(
    out, {}, in, {}, ::fast_io::size_t_opt{body_length});

需要这一轮搬了多少字节时用 transmit_some_bytes, 例如更新进度计数或交错处理多个流。返回 0 表示 EOF,不是错误。

5. 带缓冲的输入与输出

transmit 对带缓冲和不带缓冲的设备、输入和输出两侧都成立。 实现会小心处理两个顺序风险:

这就是为什么 transmit 对 scan 和 print 使用的带缓冲类型也安全,而不只是对原始 native 文件安全。

6. 失败与部分进展

两个操作都通过 herbception 报告设备失败。部分传输不是失败: transmit_all_bytes 会继续到 EOF 或上界, transmit_some_bytes 报告已搬字节数。一个字节只有在真正到达输出之后才计数, 所以短写不会悄悄丢失输入数据。

偏移是另一类失败面。给不能 seek 的设备(管道或 socket)传非空输出偏移是错误; 这些设备传 {}。

7. transmit、print 与 scan

操作 输入 输出 数据
print 值 设备 格式化文本
scan 带缓冲设备 值 解析文本
transmit 设备 设备 原始字节

不要用 print 搬二进制 blob,也不要用 transmit 写数字。 边界和第11.5章说的一样:字节用 transmit,结构化数据用 scan 和 print。

模块状态。 transmit 操作目前来自头文件接口。 当前 fast_io 模块导出列表不包含 transmit_some_bytes 或 transmit_all_bytes; 在它们被导出之前,使用 #include <fast_io.h>。

要点