二进制读写文件必须使用std::ios::binary标志,否则换行符会被转换导致数据错乱;需用write()/read()操作原始字节,注意结构体序列化、字节序、内存对齐及跨平台兼容性。

二进制读写文件在 C++ 中必须用 std::ios::binary 标志打开流,否则换行符会被自动转换,导致数据错乱。
用 std::ofstream 以二进制模式写入原始数据
直接写入内存布局(如结构体、数组)时,不能依赖默认文本模式 —— 它会把 '\n' 转成 "\r\n"(Windows 下),破坏二进制一致性。
实操要点:
- 打开文件时务必传入
std::ios::binary,例如:std::ofstream ofs("data.bin", std::ios::binary); - 用
write()写入 raw 字节,参数是const char*和字节数:ofs.write(reinterpret_cast(&value), sizeof(value)); - 结构体若含指针或虚函数,不能直接 write —— 只能序列化其成员字段,否则写入的是地址值,读取时无效
- 写入前后建议检查流状态:
if (!ofs) { /* 错误处理 */ }
用 std::ifstream 以二进制模式读取原始数据
读取必须与写入方式严格对称:相同字节顺序、相同内存布局、相同 sizeof。否则读出来的值会是垃圾。
立即学习“C++免费学习笔记(深入)”;
常见陷阱:
- 忘记加
std::ios::binary,尤其在 Windows 上会导致提前遇到 EOF 或读偏移错位 - 用
operator>>读取 —— 这是格式化输入,只适用于文本,且会跳过空白,完全不适用二进制 - 读取结构体前未确保内存对齐一致(比如不同编译器默认对齐不同),可加
#pragma pack(1)强制紧凑排列 - 读取后应调用
gcount()检查实际读到多少字节,避免部分读取却误判成功
处理跨平台兼容性:字节序和结构体布局
二进制文件没有“标准格式”,int 在 x86 是小端,在 ARM64 可能是大端;struct 的 padding 也随编译器和目标平台变化。
安全做法:
- 基础类型统一用固定宽度整型:
int32_t、uint64_t,避免int/long的歧义 - 手动控制序列化:逐字段读写,并用
htons()/ntohl()或自定义函数转为网络字节序(大端)存盘 - 结构体开头加 magic number 和版本号字段,便于后续校验和兼容旧数据
- 不要直接
write()STL 容器(如std::vector),它内部指针不在对象内存中,需单独写 size + data
真正难的不是调用 write() 或 read(),而是保证写进去的每个字节,在另一台机器、另一个编译器、甚至下个版本代码里,仍能被原样解释出来 —— 这需要设计时就放弃“偷懒直接 memcpy”的想法。










