二进制文件读写必须显式指定std::ios::binary标志,使用read()/write()而非格式化io,并检查gcount()/good();跨平台需处理字节序、内存对齐;关闭前需flush()并检查fail()。

用 std::ifstream 和 std::ofstream 以二进制模式打开文件
默认的文本模式会做换行符转换(比如 \n → \r\n),读写结构体或原始字节时直接崩。必须显式指定 std::ios::binary 标志。
常见错误:只写 std::ios::in 或 std::ios::out,漏掉 binary,结果数据错位、读到一半就 eof() 了。
std::ifstream fin("data.bin", std::ios::in | std::ios::binary);std::ofstream fout("data.bin", std::ios::out | std::ios::binary);- 追加写入用
std::ios::app | std::ios::binary,但注意app模式下seekp()无效
读写原始内存块:别用 operator 和 <code>operator>>
这两个是格式化 IO,会解析空格、换行、类型分隔符,对二进制数据完全不可控。必须用 read() 和 write() 直接操作字节流。
典型翻车现场:把一个 struct Point { int x, y; } 用 写进去,再用 <code>>> 读,结果 y 总是 0 —— 因为中间被当作文本分隔符吃了。
立即学习“C++免费学习笔记(深入)”;
- 写结构体:
fout.write(reinterpret_cast<const char>(&p), sizeof(p));</const> - 读结构体:
fin.read(reinterpret_cast<char>(&p), sizeof(p));</char> - 务必检查
gcount()或good(),read()可能只读部分字节(比如磁盘满、中断)
跨平台写结构体前,先处理字节序和内存对齐
直接 write() 结构体看似快,但 struct 在不同编译器/平台下可能有填充字节(padding),且整数默认是本地字节序(小端/大端不统一)。发给 Python 或网络另一端时大概率解不开。
不是所有场景都要手撸序列化,但只要涉及跨语言、跨机器、长期存储,就不能跳过这步。
- 用
#pragma pack(1)或alignas(1)消除 padding(注意性能代价) - 关键字段(如
int32_t)用htons()/htonl()或std::byteswap()统一为大端 - 更稳的做法:逐字段
write()+ 显式类型长度(比如固定写 4 字节int32_t,而非sizeof(int))
关闭文件前记得 flush() 和检查 fail()
析构函数会自动 close,但写失败不会抛异常,也不会提示你数据根本没落盘。尤其在嵌入式或低资源环境,缓存未刷导致静默丢数据很常见。
很多人以为 ofstream 离开作用域就万事大吉,其实 write() 成功只代表进了缓冲区,close() 才真正触发系统调用。
- 显式调用
fout.flush()后检查!fout.fail() - 关闭后检查
!fout.fail(),失败时查errno(Linux)或GetLastError()(Windows) - 如果要确保原子写入,得用临时文件 +
rename(),C++ 标准库不提供该语义
二进制 IO 的坑不在语法,而在“看起来写进去了”和“真的能被正确还原”之间那几行没写的检查与适配。










