必须显式指定std::ios::binary标志,否则Windows下会因0x1A被误判为EOF而截断数据;read()/write()需传原始内存地址和字节数,结构体需处理填充和字节序。

用 std::fstream 以 std::ios::binary 模式打开文件
默认的 std::fstream 是文本模式,会自动转换换行符(比如 \r\n → \n),破坏二进制数据。必须显式指定 std::ios::binary 标志:
std::fstream file("data.bin", std::ios::in | std::ios::out | std::ios::binary);
if (!file.is_open()) {
// 处理失败
}
- 读写同开时,
std::ios::in | std::ios::out是必要组合;只读用std::ios::in,只写用std::ios::out - Windows 下若漏掉
std::ios::binary,读到的字节数可能少于预期,尤其遇到0x1A(EOF 符)会被提前截断 - Linux/macOS 对文本/二进制模式区分不敏感,但跨平台代码必须统一加
std::ios::binary
read() 和 write() 的参数与常见错误
这两个函数操作的是原始内存块,不是字符串或对象本身,参数必须严格匹配:
int value = 42; file.write(reinterpret_cast(&value), sizeof(value)); // 正确:取地址 + 强转 + 显式大小 char buf[1024]; file.read(buf, sizeof(buf)); // 正确:传入缓冲区首地址和字节数
-
read()不会自动在末尾加\0,读完后若要当 C 字符串用,需手动置零或确保缓冲区初始化 - 读取后务必检查
file.gcount()—— 它返回实际读到的字节数,可能小于请求值(如文件结尾、磁盘满) - 直接
file.write(&str, sizeof(str))写std::string对象是错的:它只写对象内部指针/长度字段,不是字符串内容
结构体写入前要注意内存对齐和字节序
直接 write() 结构体可行,但有隐含风险:
struct Header {
uint32_t magic; // 通常 4 字节
uint16_t version; // 通常 2 字节
char name[32];
};
- 编译器可能在字段间插入填充字节(padding),导致
sizeof(Header)> 实际数据长度;用#pragma pack(1)或[[gnu::packed]]强制紧凑布局 - 不同 CPU 架构字节序不同(x86 是小端,ARM 可能大端),网络传输或跨平台读写时,需手动用
htons()/htonl()转换整数字段 - 含指针或虚函数的类不能直接二进制序列化 —— 指针值在另一进程毫无意义
写完记得 flush() 和检查 failbit
二进制写入出错不会抛异常(默认不开启 exceptions()),全靠状态位判断:
立即学习“C++免费学习笔记(深入)”;
file.write(data, size);
if (file.fail()) {
// 可能是磁盘满、权限不足、设备断开等
// 注意:fail() 包含 badbit(底层 I/O 错误)和 failbit(格式/逻辑错误)
}
file.flush(); // 确保缓冲区数据真正落盘,尤其在程序可能崩溃前
- 不调
flush()就关闭文件,部分数据可能滞留在缓冲区中丢失 -
file.good()是“全无错误”的快捷判断,但定位问题不如分别查fail()、bad()、eof() - 频繁小块写入性能差,建议预分配缓冲区 + 批量
write(),或用std::vector管理内存











