一、核心函数原型与参数解析
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);
|
关键特性:
1.3 流提取运算符 >>
流提取运算符是最常用的格式化输入工具:
1
| istream& operator>>(istream& is, T& value);
|
其中T可以是任何基本数据类型(int、float、char、string 等)
关键特性:
二、三种方法的核心差异对比
特性 |
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) |
严格按字节处理 |
适用场景 |
文本文件、配置文件 |
图像、音频、自定义格式 |
读取单位 |
通常按字符 / 行 |
通常按固定大小块 |