二进制文件读写必须显式使用"rb"/"wb"或std::ios::binary模式,fread/fwrite参数顺序不能颠倒,且须检查返回值;C++中禁用<<>>运算符,改用read()/write()。

用 fopen/fread/fwrite 读写二进制文件要注意什么
直接用 C 标准库函数操作二进制文件最简单,但容易因模式字符串写错导致文本换行符被悄悄转换,或读写长度不匹配造成截断/越界。
-
fopen必须显式加"rb"或"wb"模式,"r"/"w"默认是文本模式,Windows 下会把\n转成\r\n,破坏原始字节 -
fread和fwrite的第 2、3 参数(单个元素大小、元素个数)别反了:写成fwrite(buf, n, 1, fp)就只写 1 个n字节的块,不是n个字节;正确应是fwrite(buf, 1, n, fp)或更稳妥的fwrite(buf, sizeof(uint8_t), n, fp) - 返回值必须检查:
fread返回实际读取的元素个数,可能小于请求值(比如文件末尾或 I/O 错误),不能只靠feof判断是否读完
C++ 里用 std::fstream 读写二进制文件怎么避免踩坑
std::fstream 默认也是文本模式,不加标志位照样会乱码——尤其在 Windows 上读写 0x0A 附近的数据时。
- 构造或
open()时必须传std::ios::binary,例如:std::fstream fs("data.bin", std::ios::in | std::ios::binary) - 不要用
<</>>流插入/提取运算符,它们按格式解析(跳过空白、转数字等),二进制数据会直接错乱;改用read()/write()成员函数 -
read()不会自动补零或抛异常,读到 EOF 时gcount()返回实际字节数,fail()在读取失败(非仅 EOF)时才为 true
两种方案性能和跨平台行为差异在哪
纯吞吐量上没本质区别,底层都调系统 read/write,但细节行为影响可移植性。
- POSIX 系统下两者几乎一致;Windows 下 C 方案依赖 CRT 的
_setmode(_fileno(fp), _O_BINARY)补救,而 C++ 方案只要写了binary标志就稳 -
fread/fwrite缓冲由 libc 管理,std::fstream缓冲可调(rdbuf()->pubsetbuf()),但默认也够用;频繁小块读写时,手动控制缓冲区大小比依赖默认行为更可控 - 错误处理粒度不同:
fread返回值明确告诉你读了多少;std::fstream需组合gcount()、fail()、bad()才能准确定位问题类型
什么时候该选 C 方案,什么时候该选 C++ 方案
看项目上下文,不是语言偏好。
- 嵌入式或最小依赖场景(比如只 link libc,不带 STL)——只能用
fopen/fread/fwrite - 已有大量 C 接口或需与 C 库共用
FILE*(如 libpng、libjpeg)——硬切 C++ 流反而增加转换开销和生命周期管理负担 - 项目已用 RAII 管理资源、需要异常语义或配合现代 C++ 容器(如读到
std::vector<uint8_t>)——std::fstream更自然,但记得关掉exceptions()默认不抛异常,得手动设
二进制文件读写的“正确”不在于用哪个 API,而在于是否始终把字节当字节对待——模式标志、缓冲边界、返回值校验,三者漏一,数据就可能静默损坏。特别是调试时看到文件头对不上,八成是某处少了个 b。









