用 std::ifstream 二进制读文件必须加 std::ios::binary,否则 Windows 下会错误转换 \r\n;需检查 is_open()、用 seekg/tellg 获取大小、read() 后必查 gcount()、close() 后检查 fail()。

用 std::ifstream 以二进制模式打开文件必须加 std::ios::binary
不加这个标志,Windows 下会把 \r\n 自动转成 \n,读出来的字节数和文件实际大小对不上,尤其读图片、音频、加密数据时直接出错。Linux/macOS 虽然影响小,但跨平台代码必须统一加。
常见错误:只写 std::ifstream file("data.bin") —— 这是文本模式,默认启用换行符转换。
- 正确写法:
std::ifstream file("data.bin", std::ios::binary) - 打开后务必检查:
if (!file.is_open()) { /* 处理失败 */ } - 如果路径含中文或特殊字符,C++ 标准库在 Windows 上默认不支持宽字符路径,建议用 UTF-8 编码路径 + 编译器扩展(如 MSVC 的
/utf-8)或改用std::filesystem::u8path(C++17)
读取全部内容到内存推荐用 std::vector + read
std::ifstream::read() 是最可控的二进制读取方式,它不解析内容、不跳过空白、不添加终止符,完全按字节搬运。配合 std::vector 可避免手动 new[]/delete[] 和缓冲区溢出风险。
别用 getline() 或 >> 操作符——它们是为文本设计的,遇到 \0 或控制字符就停了。
立即学习“C++免费学习笔记(深入)”;
std::ifstream file("data.bin", std::ios::binary);
if (!file.is_open()) {
// 错误处理
}
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector buffer(size);
file.read(buffer.data(), size);
// 检查是否读满
if (file.gcount() != static_cast(size)) {
// 读取异常:磁盘错误、权限不足、文件被截断等
}
gcount() 是唯一可靠的方式判断实际读了多少字节
read() 不抛异常(除非设置了 exceptions()),也不返回成功字节数。它只更新内部状态,而 gcount() 返回上一次输入操作实际提取的字符数——这是你唯一能信的数字。
- 即使
file.good()为 true,gcount()也可能小于预期(比如文件末尾突然变小) - 不要依赖
file.eof()判断读完:它只在尝试读越界后才置位,容易误判 - 如果要分块读大文件(比如 64KB 一块),每次调用
read()后都得立刻查gcount()
关闭文件前记得检查 failbit 防止静默失败
二进制读取中,磁盘 I/O 错误可能不立即暴露。比如读到一半电源中断,read() 可能只返回部分字节,failbit 却没立刻置位;直到你调用 close() 或析构时才触发底层错误。
所以,在 file.close() 后应检查状态:
file.close();
if (file.fail()) {
// 底层 close 失败:磁盘已满、文件系统只读、权限变更等
// 此时 buffer 中的数据仍是有效的(读取已完成),但需记录该错误
}更稳妥的做法是:读完即用 file.exceptions(std::ios::failbit | std::ios::badbit) 开启异常,让错误在发生时立刻抛出——但要注意,这会让 close() 也抛异常,需包裹 try/catch。
实际项目里最容易被忽略的是:没验证 gcount(),也没检查 close() 结果,导致“以为读全了”,结果后续解析崩溃。










