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