核心要点速览

  • 区别:文本处理基于字符编码(有格式转换),二进制处理基于原始字节流(无转换)。
  • 差异:文本可人类直接阅读,二进制不可;文本有换行符 / 编码转换,二进制无;文本适合日志 / 配置,二进制适合图片 / 结构体。
  • 操作:文本用>>/<</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
2
3
4
5
6
7
8
9
10
// 写入
ofstream log("log.txt", ios::app); // 追加模式
log << "[" << __TIME__ << "] 操作成功" << endl; // 自动换行+刷新

// 读取
ifstream ifs("log.txt");
string line;
while (getline(ifs, line)) { // 逐行读,保留空格
cout << line << endl;
}

易错

  • >>getline()混用:>>读取后会残留换行符在缓冲区,导致getline()直接读空行。解决:用ignore()清除:
1
2
3
4
int num;
ifs >> num;
ifs.ignore(numeric_limits<streamsize>::max(), '\n'); // 清除到换行符
getline(ifs, line); // 正常读取
  • 换行符跨平台问题:Windows 文本在 Linux 下用cat查看可能显示^M(未转换的\r),需用文本模式读写避免。

三、二进制处理:基于字节的读写

二进制处理的核心是 “按原始字节操作”,需显式指定ios::binary模式,直接读写内存中的二进制数据。

1. 操作函数

  • 写入write(const char* buf, streamsize n):将内存中n字节数据写入文件(需强转为char*)。
  • 读取read(char* buf, streamsize n):从文件读取n字节到内存缓冲区。

2. 典型示例与注意事项

示例:读写结构体(二进制)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma pack(1) // 关闭字节对齐(跨平台必备)
struct User {
int id;
char name[20]; // 用固定数组,避免string动态内存
double score;
};
#pragma pack()

// 写入
ofstream ofs("users.bin", ios::out | ios::binary);
User u = {101, "Alice", 95.5};
ofs.write(reinterpret_cast<const char*>(&u), sizeof(u)); // 写入整个结构体字节

// 读取
ifstream ifs("users.bin", ios::in | ios::binary);
User u2;
ifs.read(reinterpret_cast<char*>(&u2), sizeof(u2));
if (ifs.good()) { // 检查读取成功
cout << u2.id << " " << u2.name << " " << u2.score << endl;
}

注意事项

  • 字节对齐:结构体默认按编译器规则对齐(如int占 4 字节,double占 8 字节),不同平台对齐方式不同,会导致读写错位。必须用#pragma pack(n)强制对齐(n=1为紧凑模式)。
  • 避免stringstring内部含指针(指向堆内存),二进制写入会存储指针地址而非字符串内容,读取后指针无效(野指针),必须用char数组。
  • 字节序:跨平台(如 x86 是小端,ARM 可能大端)时,整数 / 浮点数的字节顺序可能不同,需统一字节序(如用htonl/ntohl转换为网络字节序)。

四、问答

1. 二进制读写结构体时,为什么string会出问题?

string是动态容器,存储的是指向堆中字符的指针,而非字符本身。二进制写入时会存储指针地址,读取后指针指向无效内存(野指针),导致数据错乱。

2. 为什么二进制处理效率比文本高?

文本处理需将数据与字符编码互转(如int 123→字符串 “123”),还需处理换行符;二进制直接读写内存原始字节,无额外转换,效率更高。