用std::ofstream写二进制文件必须显式指定std::ios::binary模式,否则会因文本模式自动转换换行符和截断\0字节;需正确使用write()传地址与大小,注意结构体布局、字节序、flush()及错误检查。

用 std::ofstream 以 std::ios::binary 模式打开文件
默认的 std::ofstream 是文本模式,会自动转换换行符(比如把 \n 变成 \r\n),还会在某些平台截断 \0 字节。写二进制必须显式指定二进制模式。
常见错误是只写 std::ofstream f("data.bin"),没加标志位,结果写出来的文件内容被悄悄改了。
- 正确写法:
std::ofstream f("data.bin", std::ios::binary) - 如果还要追加写入,加上
std::ios::app,但注意:app模式下seekp无效 - 写完务必检查
f.good()或!f,尤其在嵌入式或磁盘满时,write()不抛异常,失败后failbit被置位
write() 写原始内存块,别传错指针和长度
write() 接收的是 const char* 和 std::streamsize,它不理解数据类型,只按字节拷贝。传错地址或长度会导致写入垃圾、越界或截断。
典型场景:写一个 struct 或数组。别直接传结构体变量名(那是值,不是地址),也别漏掉 sizeof。
立即学习“C++免费学习笔记(深入)”;
- 写整数数组:
int arr[] = {1,2,3}; f.write(reinterpret_cast<const char>(arr), sizeof(arr));</const> - 写结构体:
MyStruct s; f.write(reinterpret_cast<const char>(&s), sizeof(s));</const>—— 注意结构体不能含指针、虚函数、非POD成员,否则行为未定义 - 千万别写成
f.write((char*)s, sizeof(s)):C 风格强制转换绕过类型安全,且s是对象不是指针,编译不过
写入前确认字节序和对齐,跨平台读取才不会错
C++ 不保证结构体布局,也不规定字节序。同一段代码在 x86 和 ARM 上写出来的二进制可能完全不一样。
如果你写的文件要被其他程序(尤其是不同架构或语言)读取,不能依赖 sizeof(struct) 和默认内存布局。
- 用
#pragma pack(1)或[[gnu::packed]]消除填充字节,但仅限于明确控制布局的场景 - 数值字段建议手动序列化:用
htons()/htonl()统一转为大端,再write() - 避免直接写
std::string对象——它内部是指针,写进去的只是地址值,不是字符串内容
关闭文件前记得 flush(),尤其用 write() 后没自动刷新
std::ofstream 的缓冲区默认启用,write() 调用后数据未必立刻落盘。如果程序崩溃或提前退出,最后一段数据就丢了。
多数情况析构函数会 flush,但不可依赖:比如 exit() 会跳过析构,或者 std::ofstream 是全局变量(静态存储期)时析构顺序不确定。
- 稳妥做法:
f.flush();或f.close();(close()内部会 flush) - 别用
std::endl替代flush():它只对文本流有意义,二进制里没有“行”概念 - 如果频繁小块写入,考虑用
std::ofstream构造时加std::ios::unitbuf,但性能有代价


















