文件IO:二进制与文本处理
核心要点速览
- 区别:文本处理基于字符编码(有格式转换),二进制处理基于原始字节流(无转换)。
- 差异:文本可人类直接阅读,二进制不可;文本有换行符 / 编码转换,二进制无;文本适合日志 / 配置,二进制适合图片 / 结构体。
- 操作:文本用
>>/<</getline(),二进制用read()/write()+ios::binary。
一、区别
| 维度 | 文本处理(Text Mode) | 二进制处理(Binary Mode) |
|---|---|---|
| 存储形式 | 字符编码(如 ASCII、UTF-8),每个字符对应编码值。 | 数据原始二进制(如 int 的 4 字节、结构体的连续字节)。 |
| 格式转换 | 自动处理换行符(Windows:\n→\r\n;Linux:不转换),部分编码可能转换(如宽字符)。 |
无任何转换,字节数据原样读写(\n就是 0x0A,\r就是 0x0D)。 |
| 可读性 | 人类可直接阅读(如记事本打开txt文件)。 |
人类不可读(打开为乱码,需程序解析)。 |
| 效率 | 读写需编码 / 解码,效率较低。 | 直接操作字节流,效率高(无额外处理)。 |
| 适用场景 | 日志文件、配置文件(.ini)、文本数据(如csv)。 |
图像 / 音频(.jpg/.mp3)、结构体、加密数据、大文件。 |
二、文本处理:基于字符的读写
文本处理的核心是 “按字符或行操作”,依赖流的格式化输入输出,自动处理字符编码和换行符。
1. 操作函数
- 写入:
<<(插入运算符,输出数据)、put()(单个字符)、endl(换行 + 刷新)。 - 读取:
>>(提取运算符,按空白分割)、getline()(读取一行,含空格)、get()(单个字符,含空格 / 换行)。
2. 典型示例与易错
示例:读写文本日志
1 | // 写入 |
易错:
>>与getline()混用:>>读取后会残留换行符在缓冲区,导致getline()直接读空行。解决:用ignore()清除:
1 | int num; |
- 换行符跨平台问题:Windows 文本在 Linux 下用
cat查看可能显示^M(未转换的\r),需用文本模式读写避免。
三、二进制处理:基于字节的读写
二进制处理的核心是 “按原始字节操作”,需显式指定ios::binary模式,直接读写内存中的二进制数据。
1. 操作函数
- 写入:
write(const char* buf, streamsize n):将内存中n字节数据写入文件(需强转为char*)。 - 读取:
read(char* buf, streamsize n):从文件读取n字节到内存缓冲区。
2. 典型示例与注意事项
示例:读写结构体(二进制)
1 |
|
注意事项:
- 字节对齐:结构体默认按编译器规则对齐(如
int占 4 字节,double占 8 字节),不同平台对齐方式不同,会导致读写错位。必须用#pragma pack(n)强制对齐(n=1为紧凑模式)。 - 避免
string:string内部含指针(指向堆内存),二进制写入会存储指针地址而非字符串内容,读取后指针无效(野指针),必须用char数组。 - 字节序:跨平台(如 x86 是小端,ARM 可能大端)时,整数 / 浮点数的字节顺序可能不同,需统一字节序(如用
htonl/ntohl转换为网络字节序)。
四、问答
1. 二进制读写结构体时,为什么string会出问题?
string是动态容器,存储的是指向堆中字符的指针,而非字符本身。二进制写入时会存储指针地址,读取后指针指向无效内存(野指针),导致数据错乱。
2. 为什么二进制处理效率比文本高?
文本处理需将数据与字符编码互转(如int 123→字符串 “123”),还需处理换行符;二进制直接读写内存原始字节,无额外转换,效率更高。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 肖恩的博客!
评论

