必须加 std::ios::binary,否则Windows下会将\r\n转为\n并可能因\x1A提前截断,Linux虽影响小但跨平台需统一;不加则读取字节数与文件不符。

直接用 std::ifstream 以 std::ios::binary 模式打开,配合 read() 和 gcount() 才能正确读取二进制数据;默认文本模式会破坏 \x00 和换行符,千万别跳过 binary 标志。
为什么必须加 std::ios::binary?
Windows 下文本模式会把 \r\n 自动转成单个 \n,还会把遇到的 \x1A(EOF 符)提前截断;Linux 虽影响小,但跨平台代码必须统一行为。不加这个标志,读出来的字节数和原始文件对不上是常态。
-
std::ifstream ifs("data.bin");→ 文本模式,危险 -
std::ifstream ifs("data.bin", std::ios::binary);→ 正确起点 - 写入同理:用
std::ofstream ofs("out.bin", std::ios::binary);
read() 怎么用才不丢数据?
read() 不保证一次读完全部内容,它只按请求长度尝试读,并通过 gcount() 返回实际字节数。尤其在从管道、网络流或某些文件系统读时,容易少读。
- 先用
seekg(0, std::ios::end);+tellg()获取真实大小 - 分配足够缓冲区(比如
std::vector)buf(size); - 调用
ifs.read(buf.data(), size);后立刻检查:if (ifs.gcount() != size) { /* 错误处理 */ } - 不要依赖
!ifs.eof()判断是否读完——它只在尝试读失败后才置位
读结构体或 POD 类型要注意什么?
可以直接 read() 进结构体变量,但前提是该类型是标准布局(standard-layout)、无虚函数、无非平凡构造/析构——也就是典型的 C 风格 struct。否则行为未定义。
立即学习“C++免费学习笔记(深入)”;
struct Header {
uint32_t magic;
uint16_t version;
uint8_t flags;
}; // ✅ 可直接 read
Header h;
ifs.read(reinterpret_cast>(&h), sizeof(h));
if (ifs.gcount() != sizeof(h)) { / 失败 */ }
- 注意大小端:文件存的是大端,而 x86 是小端,需手动转换(如用
ntohl()) - 结构体中间有 padding?
#pragma pack(1)或[[gnu::packed]]控制对齐,否则sizeof(Header)≠ 实际磁盘布局 - 别对
std::string或std::vector成员直接read()—— 它们内部指针无效
最常被忽略的一点:读完记得检查 ifs.good() 或至少 ifs.fail(),而不是只看 gcount()。有些错误(比如权限不足)会导致 gcount() 为 0,但 failbit 已置位,不查就继续用缓冲区等于用野值。










