二进制文件操作必须显式指定 std::ios::binary 标志,使用 read/write 时需用 reinterpret_cast 安全转换地址,检查 failbit/eofbit 并用 gcount() 验证读取字节数,跨平台需统一字节序与对齐。

用 std::fstream 以二进制模式打开文件,不是默认行为
默认的 std::fstream(包括 std::ifstream 和 std::ofstream)是文本模式,会做换行符转换(比如 Windows 的 \r\n → \n),还可能截断遇到的 \0。二进制读写必须显式加 std::ios::binary 标志。
常见错误现象:read() 返回字节数少于预期、读到一半就停、写入后文件大小异常、跨平台读取乱码或崩溃。
- 正确写法:
std::ifstream fin("data.bin", std::ios::binary); - 写入同理:
std::ofstream fout("out.bin", std::ios::binary | std::ios::out); - 如果同时读写,用
std::fstream并带上std::ios::in | std::ios::out | std::ios::binary - 别漏掉
std::ios::binary—— 它不能靠编译器推导,也不继承自父类标志
read() 和 write() 只认 char*,别传结构体地址就完事
read() 和 write() 的第一个参数类型是 char*,长度单位是字节。直接把结构体变量名(比如 MyStruct s;)的地址强转过去看似可行,但有严重隐患。
使用场景:保存/加载 POD 类型(如 struct Vec3 { float x,y,z; };);非 POD(含虚函数、引用、std::string 等)绝不能这么干。
立即学习“C++免费学习笔记(深入)”;
- 安全前提:确保结构体是标准布局(
std::is_standard_layout_v<mystruct></mystruct>为true),且没有 padding 影响(可用#pragma pack(1)或alignas控制,但要同步两端) - 正确示例:
fin.read(reinterpret_cast<char>(&s), sizeof(s));</char> - 错误示例:
fin.read((char*)&s, sizeof(s));—— C 风格强制转换不安全,C++ 要求显式reinterpret_cast - 更稳妥做法:对复杂数据,手写序列化,而不是依赖内存布局
读写前务必检查流状态,failbit 和 eofbit 不是同一回事
二进制操作中,read() 成功返回的是流对象本身(可链式调用),但它不抛异常,也不会自动告诉你“只读了 3 个字节却期望 8 个”。靠 gcount() 和状态位判断才是正解。
常见错误现象:程序没报错,但数据错位、后续读取全乱、read() 后直接用未初始化内存。
- 每次
read()后立刻检查:if (!fin) { /* 处理错误 */ },这等价于检查failbit或badbit - 用
fin.gcount()获取**本次实际读取字节数**,和预期对比(比如sizeof(T)) -
eofbit只在尝试读超尾部时置位,不是“已到结尾”的预告——它常在一次失败read()后才生效,不能用来预判 - 别依赖
while(fin)循环读二进制块,容易多读一次或漏判部分失败
跨平台写二进制文件,字节序和对齐必须双方一致
Windows x64、Linux x86_64、macOS ARM64 默认都是小端,但如果你的文件要被嵌入式设备(如 STM32 大端模式)或 Java/C# 程序读取,字节序不匹配会导致数值全错。
性能 / 兼容性影响:手动翻转字节(如 htons/ntohl)有轻微开销,但远小于出错成本;结构体对齐差异则可能导致 sizeof 在不同编译器下不一致。
- 基础原则:约定一种端序(推荐网络字节序,即大端),所有整数字段写入前用
htonl、htons,读取后用ntohl、ntohs - 浮点数不建议直接二进制传输,
float在 IEEE 754 下虽普遍兼容,但某些老平台或特殊编译选项下仍可能异常 - 结构体定义里加
static_assert(std::is_standard_layout_v<t> && sizeof(T) == N, "...");</t>,防止意外改动破坏二进制格式 - 文件头加 magic number 和版本号(如
uint32_t magic = 0x42494E00;),便于快速识别格式和拒绝旧版解析
二进制文件没有容错余地,一个字节错,后面全崩。最危险的不是不会写,而是写了之后没验证、没测边界、没留升级余地。










