读二进制文件必须用 std::ios::binary 模式,否则 windows 下会错误转换 \r\n 和截断 0x1a;read() 需严格匹配缓冲区与字节数,读后必查 gcount(),且不可将二进制数据直接当字符串使用。

用 std::ifstream::read() 读二进制文件前必须关掉文本模式
默认构造的 std::ifstream 是文本模式,Windows 下会把 \r\n 自动转成 \n,还会在遇到 0x1A(EOF 字符)时提前截断——这在读二进制文件时是致命错误。
- 必须显式传入
std::ios::binary标志:std::ifstream file("data.bin", std::ios::binary); - 如果先构造再打开,得用
open()并传标志:file.open("data.bin", std::ios::binary); - 别依赖
file.is_open()就以为没问题——它只检查是否成功打开,不校验模式
read() 的两个参数必须严格匹配:缓冲区大小和实际要读的字节数
read() 不自动补零、不自动终止、不识别字符串边界。它只按你给的长度硬拷贝内存,越界或不足都会导致未定义行为或数据丢失。
- 第一个参数是
char*类型缓冲区地址,推荐用std::vector<char></char>配合.data(),避免裸指针管理 - 第二个参数是
std::streamsize(通常是long long),必须是你「真想读」的字节数,不是缓冲区总大小 - 常见错误:用
sizeof(buf)当长度——对动态分配或 vector 来说完全不对 - 读完务必检查
gcount():它返回实际读到的字节数,可能小于请求值(比如文件末尾)
std::vector<char> buf(1024); file.read(buf.data(), buf.size()); std::streamsize n = file.gcount(); // 这才是真实读取量</char>
读完整个文件不能只靠一次 read(),得循环+判错
文件可能比缓冲区大,也可能因磁盘 I/O 暂时只返回部分数据(尤其网络文件系统)。单次 read() 绝对不足以保证读完。
- 用
while (file)不可靠——流状态在 read 后才更新,容易多循环一次 - 正确做法是每次
read()后立刻检查gcount() > 0,且!file.fail() - 更稳妥的是先用
file.seekg(0, std::ios::end)+file.tellg()获取文件大小,再分配足够空间一次性读(适合中小文件) - 注意
tellg()返回std::streampos,转整数要用static_cast<:streamsize></:streamsize>
读出来的 char 数据不能直接当字符串用
二进制数据里有嵌入的 \0、控制字符、非法 UTF-8 序列,任何尝试用 std::string 构造函数或 c_str() 去“解释”它,都会在第一个 \0 截断或触发未定义行为。
- 如果只是搬运/解析结构体,保持
std::vector<char></char>或std::span<const char></const>即可 - 需要转字符串?先确认编码,再用
std::string_view(buf.data(), n)显式指定长度,绝不用隐式构造 - 调试时打印内容,用
printf("%02x ", (unsigned char)buf[i])看原始字节,别用%s
std::ios::binary 标志和 gcount() 检查——这两处一漏,程序在某些文件上跑得“好像没问题”,换一个就崩或读错,而且很难复现。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











