用 fread 读取原始二进制数组最直接,但需确保同平台、同编译器、同字节序、无 padding,且文件以 "rb" 模式打开;跨平台时须手动处理字节序和类型宽度,读取后必须检查返回值是否等于预期元素数。

用 fread 读取原始二进制数组最直接
如果你的二进制文件里存的就是纯 int、float 或自定义结构体的连续内存块,fread 是最快最稳妥的选择。它不解析内容,只按字节搬数据,和写入时用 fwrite 严格对应。
常见错误是忽略类型大小和字节序:比如在 x86 上用 fread(&arr[0], sizeof(int), n, fp) 读 int 数组没问题,但若文件由 ARM 设备生成且含 32 位大端整数,就会错读——fread 不做任何转换。
- 确保文件以
"rb"模式打开(Windows 下尤其关键,否则换行符可能被误处理) - 提前知道数组长度
n和元素类型,否则无法分配足够内存 - 读取后检查返回值:
size_t ret = fread(...);若ret != n,说明文件末尾提前或读取失败 - 结构体数组要保证写入时没 padding 干扰,可用
#pragma pack(1)或std::is_trivially_copyable_v<t></t>验证
C++ std::ifstream 配合 read() 更现代但需注意指针转换
std::ifstream 的 read() 方法本质和 fread 类似,但接口更 C++ 化。问题常出在参数类型:它要求 char* 指针,而你手头是 int* 或 double*,直接强转容易触发 strict aliasing 警告甚至 UB。
正确做法是用 reinterpret_cast<char>(ptr)</char> 显式转换,并确认目标缓冲区已分配且足够大。
- 必须调用
is.open("file.bin", std::ios::binary);—— 缺少std::ios::binary在 Windows 下会导致read()提前终止 -
is.read(reinterpret_cast<char>(arr), n * sizeof(arr[0]));</char>后,务必检查is.gcount() == n * sizeof(arr[0]) - 如果用
std::vector存储,先vec.resize(n)再传vec.data(),别用&vec[0](空 vector 会崩)
读取时遇到 std::ios_base::failure 或文件截断怎么办
异常不是凭空出现的。开启 is.exceptions(std::ios::failbit | std::ios::badbit); 后,read() 失败会抛 std::ios_base::failure;但更常见的是静默失败——比如文件实际只有 1024 字节,却尝试读 2048 字节,gcount() 只返回 1024,后续用未初始化内存就崩了。
- 永远不要依赖
is.eof()判断读完——它只在尝试读越界后才置位,之前都是false - 安全做法:先
is.seekg(0, std::ios::end); size_t sz = is.tellg(); is.seekg(0);获取真实大小,再算能读多少个元素 - 若文件格式允许,写入时在头部存一个长度标记(如 4 字节
uint32_t),读取时先读这个长度,再按需分配
跨平台读 double 数组要当心 IEEE 754 表示差异
绝大多数现代系统用 IEEE 754 binary64,但仍有例外:某些嵌入式 DSP 或老 Fortran 环境可能用不同字节序或非标准格式。即使字节序一致,double 的内存布局也未必和 memcpy 兼容(例如有 denormal 数或 signaling NaN 的处理差异)。
- 优先用文本格式交换浮点数,除非性能压倒一切
- 若必须二进制,约定固定字节序(如小端),读取后用
std::byteswap(C++23)或手动翻转 - 测试时用已知值(如
M_PI、1.0、0.0)写入再读回,比对memcmp原始字节而非==浮点值
二进制读取真正难的不是语法,而是两端对“数据布局”的隐含共识——文件怎么写的,就必须怎么读,差一个字节或一个字节序,结果就全错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











