必须显式指定std::ios::binary标志,否则二进制读写会因换行符转换、EOF误判、标志后设无效等问题出错;read/write需谨慎处理字节数、结构体布局、跨平台兼容性及I/O完整性检查。

用 std::ifstream 和 std::ofstream 以二进制模式打开文件
默认情况下,C++ 文件流按文本模式处理换行符和 EOF,读写二进制数据会出错——比如 Windows 下的 \r\n 被转成单个 \n,或遇到 0x1A(Ctrl+Z)被误判为文件结束。必须显式指定 std::ios::binary 标志。
-
std::ifstream读二进制:构造时加std::ios::binary,否则read()可能提前截断 -
std::ofstream写二进制:同样必须带std::ios::binary,否则write()可能写入错误字节长度 - 不要混用文本模式打开再调用
binary相关操作——标志必须在构造/打开时设置,后续setf()不生效
示例:
std::ifstream fin("data.bin", std::ios::binary);</code><br><code>std::ofstream fout("out.bin", std::ios::binary);
read() 和 write() 的参数陷阱
这两个函数不识别类型,只认内存块地址和字节数。传错 sizeof 或指针类型,就会读写错位、越界或静默失败。
- 读结构体时,确保结构体是标准布局(
std::is_standard_layout_v<T>),且无虚函数、无非静态成员引用 - 别对
std::string或std::vector直接read()——它们内部指针不在对象内存里,只能序列化其内容 -
read()不保证一次读完请求字节数;要检查gcount(),尤其在网络文件系统或管道中可能返回短读 -
write()同理,写入后建议调用flush()并检查fail(),避免缓存未落盘就认为写成功
示例(安全读整块):
char buf[1024];</code><br><code>fin.read(buf, sizeof(buf));</code><br><code>if (fin.gcount() != sizeof(buf)) { /* 实际读取字节数不足 */ }
立即学习“C++免费学习笔记(深入)”;
跨平台二进制兼容性问题在哪
同一段二进制读写代码,在 x86_64 Linux 和 Windows 上可能行为一致,但一旦涉及结构体或数值类型,就容易崩——不是 C++ 标准的问题,而是底层约定差异。
- 整数大小:
int在不同平台可能是 4 字节或 8 字节;固定用int32_t/uint64_t等明确宽度类型 - 字节序:x86 是小端,ARM 可能大端;若文件需跨架构共享,必须手动转换(如用
htole32()/le32toh()) - 结构体填充:编译器自动插入 padding,
#pragma pack(1)可禁用,但需两端一致,否则读出来字段错位 - 浮点格式:IEEE 754 是主流,但某些嵌入式平台仍用非标格式;除非确认环境,否则避免直接读写
float/double
替代方案:什么时候不该用 fstream 做二进制 I/O
当性能敏感、需要随机访问大文件、或与 C 库交互频繁时,fstream 的封装反而成负担。
- 大文件顺序读写:
read()/write()系统调用 + 手动缓冲池,比fstream少一层拷贝 - 内存映射:Linux 用
mmap(),Windows 用CreateFileMapping(),适合 GB 级只读/随机读场景 - 已有 C 接口(如 libpng、ffmpeg)要求传
FILE*:用std::fopen()更直接,fstream没法转成FILE* - 异步 I/O:
fstream同步阻塞,高并发下易卡主线程;需用io_uring(Linux)或IOCP(Windows)
简单场景下 fstream 完全够用,但一旦出现“读出来全是 0”“结构体字段值乱跳”“文件大小对不上”,就得回头检查是不是掉进了上面任何一个坑里。


















