二进制文件读写必须显式指定 std::ios::binary 模式,使用 read()/write() 操作内存块,并用 seekg()/seekp() 控制位置;需注意结构体对齐、字节序及状态检查。

用 std::ifstream 和 std::ofstream 以二进制模式打开文件
默认的文本模式会做换行符转换(比如 \n ↔ \r\n),读写二进制数据必须显式指定 std::ios::binary 标志,否则文件内容会被破坏。
常见错误:漏掉 std::ios::binary,导致读出来的 char 数组和原始文件字节不一致,尤其在 Windows 上写入图片、音频或序列化结构体时直接出错。
-
std::ifstream fin("data.bin", std::ios::binary);—— 必须加std::ios::binary,不能只写"data.bin" -
std::ofstream fout("out.bin", std::ios::binary | std::ios::out);—— 写入也一样,std::ios::out可省略,但binary不可省 - 如果用
open()分两步打开,同样要在参数里带上std::ios::binary
用 read() 和 write() 直接操作内存块
二进制读写不走格式化解析(如 >> 或 ),必须用 <code>read() / write() 按字节块搬运。它们操作的是 char* 缓冲区和字节数,和数据类型无关。
典型误用:对结构体变量直接 fin >> my_struct; —— 这是文本流行为,完全不可用;或者传入 &my_struct 却没 cast 成 char*,编译报错。
-
fin.read(reinterpret_cast<char>(&my_struct), sizeof(my_struct));</char>—— 注意reinterpret_cast强转,sizeof必须准确 -
fout.write(static_cast<const char>(buf), size);</const>——write()第一个参数是const char*,static_cast更安全 - 务必检查
gcount()(read()后)或fail()状态,文件末尾或磁盘满时不会抛异常,而是静默失败
结构体序列化要注意内存对齐和跨平台兼容性
直接 read()/write() 结构体最快,但前提是结构体是 POD 类型且没有 padding 干扰,否则不同编译器或平台下 sizeof(T) 不同,读出来就是乱码。
例如定义 struct { int a; char b; } 在 GCC 和 MSVC 下可能因对齐规则不同导致 sizeof 差 3 字节,写入后另一端读就错位。
- 用
#pragma pack(1)或[[gnu::packed]]强制紧凑布局(但会影响性能,且需两端一致) - 避免含指针、虚函数、std::string 等非 POD 成员——它们不能直接二进制拷贝
- 跨平台传输时,手动处理字节序(
htons()/ntohl()),别依赖本机int的大小和 endianness
读写位置控制用 seekg() / seekp() 和 tellg() / tellp()
随机访问二进制文件(比如跳过 header 读 payload,或更新某段数据)必须用 seekg()(input)和 seekp()(output)移动读写指针。文本模式下这些函数行为未定义,二进制模式才可靠。
容易忽略:seekg() 默认以 beg 为基准,但若想从当前位置偏移,得写 fin.seekg(offset, std::ios::cur);用错基准会导致指针飞到奇怪位置。
-
fin.seekg(0, std::ios::end); size_t sz = fin.tellg(); fin.seekg(0, std::ios::beg);—— 常见获取文件大小写法 -
fin.seekg(header_size); fin.read(...);—— 跳过固定长度 header 后读正文 - 调用
seekg()后,下次read()从新位置开始;但若之前read()到 EOF,需先clear()才能再次 seek
二进制 I/O 的核心就三件事:开文件带 binary、搬数据用 read/write、动指针靠 seekg/seekp。真正难的不是语法,而是对内存布局、对齐、字节序这些底层细节的判断——写完一定要用十六进制编辑器(如 HxD、xxd)比对原始文件和程序读写结果是否一字不差。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











