一、核心函数原型与参数解析

1.1 get () 函数家族

get()函数是 C++ 中最基础的字符读取工具,有多个重载版本:

1
2
3
4
5
6
7
8
9
10
11
// 读取单个字符(包含空白字符)
int get();

// 读取字符到指定缓冲区,最多n-1个字符,遇到分隔符停止
istream& get(char* s, streamsize n);

// 带自定义分隔符的版本
istream& get(char* s, streamsize n, char delim);

// 读取字符到字符对象
istream& get(char& c);

关键特性

  • 不会跳过空白字符(空格、制表符、换行符等)

  • 读取失败时返回 EOF(-1)

  • 保留分隔符在输入流中(不提取)

1.2 getline () 函数

getline()专为读取完整行设计,主要有两种形式:

1
2
3
4
5
6
7
8
9
// 从输入流读取一行到字符数组
istream& getline(char* s, streamsize n);

// 带自定义分隔符的版本
istream& getline(char* s, streamsize n, char delim);

// string版本(在std命名空间中)
istream& getline(istream& is, string& str);
istream& getline(istream& is, string& str, char delim);

关键特性

  • 读取一整行文本,直到遇到换行符或指定分隔符

  • 会从输入流中提取并丢弃分隔符(不保留)

  • 最多读取 n-1 个字符,自动添加空终止符 '\0'

1.3 流提取运算符 >>

流提取运算符是最常用的格式化输入工具:

1
istream& operator>>(istream& is, T& value);

其中T可以是任何基本数据类型(int、float、char、string 等)

关键特性

  • 默认跳过空白字符(使用noskipws操纵符可改变此行为)

  • 按数据类型解析输入(如将 "123" 转换为整数 123)

  • 遇到无法解析目标类型的字符时停止

二、三种方法的核心差异对比

特性 get() getline() >>
空白字符处理 不跳过,全部读取 不跳过,包含在结果中 默认跳过
分隔符处理 保留在输入流中 提取并丢弃 作为终止符,保留在流中
字符串终止 自动添加 '\0' 自动添加 '\0' 自动添加 '\0'
典型用途 逐字符处理、二进制文件 整行文本处理 格式化数据读取
缓冲区管理 需要手动控制大小 自动管理,可指定大小 自动管理
错误检测 通过返回值和流状态 通过流状态 通过流状态

三、典型应用场景与代码示例

3.1 使用 get () 逐字符处理文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <fstream>
using namespace std;

int main() {
ifstream file("example.txt", ios::in);

// 检查文件是否成功打开
if (!file.is_open()) {
cerr << "无法打开文件" << endl;
return 1;
}

char c;
int charCount = 0;
int newlineCount = 0;

// 使用get()逐字符读取
while (file.get(c)) { // c = file.get()
charCount++;
if (c == '\n') {
newlineCount++;
}
}

// 检查读取过程中是否发生错误
if (file.bad()) {
cerr << "读取文件时发生错误" << endl;
return 1;
} else if (file.eof()) {
cout << "文件读取完成" << endl;
}

cout << "总字符数: " << charCount << endl;
cout << "换行符数: " << newlineCount << endl;

file.close();
return 0;
}

适用场景

  • 需要精确控制每个字符的处理

  • 处理包含大量特殊字符的文件

  • 二进制文件操作

  • 需要统计特定字符出现次数的场景

3.2 使用 getline () 读取完整行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
ifstream file("example.txt");

if (!file) {
cerr << "无法打开文件" << endl;
return 1;
}

string line;
int lineNumber = 0;

// 读取文件的每一行
while (getline(file, line)) {
lineNumber++;
// 处理空行
if (line.empty()) {
cout << "行 " << lineNumber << ": (空行)" << endl;
continue;
}
cout << "行 " << lineNumber << ": " << line << endl;
}

// 检查结束原因
if (file.eof()) {
cout << "成功读取所有行,共 " << lineNumber << " 行" << endl;
} else if (file.fail()) {
cerr << "读取文件时发生错误" << endl;
return 1;
}

file.close();
return 0;
}

自定义分隔符示例

1
2
3
4
5
6
// 读取CSV文件,使用逗号作为分隔符
string field;
while (getline(file, field, ',')) {
// 处理CSV的每个字段
cout << "字段: " << field << endl;
}

适用场景

  • 处理按行组织的文本文件

  • 读取配置文件

  • 处理 CSV 等使用特定分隔符的结构化文本

  • 需要保留行内所有空白字符的场景

3.3 使用流提取运算符 >> 读取格式化数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;

struct Student {
string name;
int age;
float score;
};

int main() {
ifstream file("students.txt");

if (!file) {
cerr << "无法打开文件" << endl;
return 1;
}

Student s;
cout << left << setw(15) << "姓名" << setw(5) << "年龄" << "成绩" << endl;
cout << string(25, '-') << endl;

// 读取格式化数据
while (file >> s.name >> s.age >> s.score) {
cout << left << setw(15) << s.name
<< setw(5) << s.age
<< fixed << setprecision(1) << s.score << endl;
}

if (!file.eof()) {
cerr << "数据格式错误,无法继续读取" << endl;
return 1;
}

file.close();
return 0;
}

禁止跳过空白字符

1
2
3
4
5
6
// 使用noskipws操纵符
file >> noskipws; // 之后的提取操作将不跳过空白字符
char c;
while (file >> c) {
// 现在会读取包括空格、换行在内的所有字符
}

适用场景

  • 读取结构化的格式化数据

  • 配置文件中的键值对

  • 数值数据的批量处理

  • 需要类型转换的输入

四、文本模式与二进制模式的差异

C++ 文件操作有两种基本模式:文本模式(默认)和二进制模式。

4.1 模式指定方法

1
2
3
4
5
6
// 文本模式(默认)
ifstream textFile("data.txt");
ifstream textFileExplicit("data.txt", ios::in);

// 二进制模式
ifstream binFile("data.bin", ios::in | ios::binary);

4.2 核心差异

特性 文本模式 二进制模式
换行符处理 自动转换(\n ↔ 系统换行符) 不转换,原样读写
EOF 处理 可能会有特殊处理(如 ^Z) 严格按字节处理
适用场景 文本文件、配置文件 图像、音频、自定义格式
读取单位 通常按字符 / 行 通常按固定大小块