1. C++流的基本概念
流(Stream) 是C++中用于处理输入和输出的抽象概念。流可以看作是数据的通道,例如从键盘到程序,或者从程序到文件。C++标准库提供了多种流类型来处理不同的数据传输需求。
常见的流类型
- 标准输入流:
std::cin - 标准输出流:
std::cout - 标准错误流:
std::cerr - 文件输入流:
std::ifstream - 文件输出流:
std::ofstream - 文件流(读写):
std::fstream - 字符串流:
std::stringstream,std::istringstream,std::ostringstream
2. 输出流 std::cout
std::cout 是C++中用于输出数据到标准输出(通常是终端)的流对象。
2.1 基本输出
示例说明:使用 std::cout 输出文本和变量。
1 |
|
输出:
1 | Hello, World! |
解释:
<<运算符用于将数据插入到输出流中。std::endl用于输出一个换行符并刷新缓冲区。
2.2 格式化输出
C++ 提供了多种方式来格式化输出,例如设置字段宽度、小数点精度等。
示例说明:使用不同的格式化操纵器。
1 |
|
输出:
1 | Pi with default precision: 3.14159 |
解释:
std::fixed:以固定小数点格式显示浮点数。std::setprecision(4):设置小数点后4位精度。std::setw(5):设置输出字段宽度为5个字符。std::left:设置左对齐。
3. 文件输出流 std::ofstream
std::ofstream 用于创建和写入文件。
3.1 创建和打开文件
在使用 std::ofstream 写入文件之前,需要创建一个 ofstream 对象并打开目标文件。
3.2 向文件写入数据
使用 << 操作符可以向文件中写入数据,类似于 std::cout。
3.3 关闭文件
写入完成后,应关闭文件以释放资源。
3.4 示例代码
示例说明:创建一个文本文件并写入数据。
1 |
|
运行结果:
1 | 数据已成功写入 output.txt 文件。 |
output.txt 文件内容:
1 | 这是第一行。 |
解释:
- 创建
std::ofstream对象时,如果文件不存在则会自动创建,若存在则默认覆盖。 - 使用
<<操作符写入字符串、整数和浮点数到文件。 outfile.close()用于关闭文件。
4. 文件输入流 std::ifstream
std::ifstream 用于打开和读取文件内容。
4.1 打开和读取文件
使用 std::ifstream 对象打开目标文件,并读取其中的数据。
4.2 处理读取的数据
可以逐行读取、逐词读取或按其他格式读取数据。
4.3 关闭文件
读取完成后,应关闭文件。
4.4 示例代码
示例说明:读取 output.txt 文件并输出内容到控制台。
1 |
|
输出:
1 | 这是第一行。 |
解释:
- 使用
std::getline函数逐行读取文件内容。 - 读取到的每一行存储在
std::string类型的line变量中。 - 通过
std::cout将读取到的每一行输出到控制台。
5. 文件流 std::fstream (读写结合)
std::fstream 允许同时进行文件的读写操作。
5.1 同时进行读写操作
通过打开文件的不同模式,可以实现对同一文件的读取和写入。
5.2 示例代码
示例说明:在同一个文件中读取现有内容并追加新内容。
1 |
|
解释:
std::ios::in:以读取模式打开文件。std::ios::out:以写入模式打开文件。std::ios::app:以追加模式写入文件(数据会被添加到文件末尾)。- 使用
seekg将读取位置移动到文件开头,以便读取整个文件内容。 - 先写入数据,再读取整个文件内容,实现读写结合。
注意:
- 如果文件不存在,使用
std::ios::in和std::ios::out组合可能无法创建新文件。在这种情况下,可以添加std::ios::trunc或std::ios::ate标志,或者先创建文件。
6. 字符串流 std::stringstream
std::stringstream 是 C++ 标准库提供的一个类,用于在字符串和其他数据类型之间进行格式化输入和输出。它允许我们像操作文件或控制台流一样操作字符串,非常适合于字符串解析、格式化和转换。
6.1 std::stringstream 的基本概念
- **
std::stringstream**:同时具备std::istringstream(输入流)和std::ostringstream(输出流)的功能,既可以从字符串中读取数据,也可以向字符串中写入数据。 - **
std::istringstream**:仅用于从字符串中读取数据。 - **
std::ostringstream**:仅用于向字符串中写入数据。
6.2 字符串与其他数据类型的转换
std::stringstream 常用于以下场景:
- 将其他数据类型转换为字符串。
- 将字符串解析为其他数据类型。
- 构建复杂的字符串。
6.3 示例代码
6.3.1 将多个数据类型组合成一个字符串
示例说明:使用 std::stringstream 将整数、浮点数和字符串组合成一个字符串。
1 |
|
输出:
1 | ID: 101, Name: Alice, Score: 95.5 |
解释:
- 创建
std::stringstream对象ss。 - 使用
<<操作符将不同类型的数据插入到流中。 - 使用
ss.str()获取累积的字符串内容。
6.3.2 从字符串中解析数据
示例说明:使用 std::stringstream 从一个格式化的字符串中提取数据。
1 |
|
输出:
1 | Year: 2023 |
解释:
- 将字符串
data初始化到std::stringstream对象ss中。 - 使用
>>操作符从流中提取数据,按顺序赋值给变量。
6.3.3 字符串与数字的相互转换
示例说明:将字符串转换为整数和浮点数,以及将数字转换为字符串。
1 |
|
输出:
1 | 字符串 "12345" 转换为整数:12345 |
解释:
- 使用
std::stringstream将字符串解析为数字。 - 使用
std::stringstream将数字格式化为字符串。
6.3.4 使用 std::istringstream 和 std::ostringstream
std::istringstream 和 std::ostringstream 是 std::stringstream 的专门化版本,分别用于只读和只写操作。
示例说明:分别使用 std::istringstream 读取数据,和 std::ostringstream 构建字符串。
1 |
|
输出:
1 | Parsed Data: |
解释:
std::istringstream用于从字符串input中提取数据。std::ostringstream用于将数据格式化为字符串output。
6.3.5 处理复杂的字符串格式
示例说明:从包含逗号分隔值的字符串中提取数据。
1 |
|
输出:
1 | Name: John |
解释:
- 使用
std::getline从stringstream中读取以逗号分隔的字符串。 - 使用
ignore忽略分隔符。
6.4 总结
std::stringstream 是一个强大的工具,适用于字符串与其他数据类型之间的转换、格式化输出和解析复杂的字符串数据。通过熟练掌握 std::stringstream 的使用,可以大大简化数据处理任务,提高代码的可读性和维护性。
7. 其他流操作
除了基本的读写操作,C++流还提供了许多其他功能,如错误检查、不同的读取方式、不同的打开模式等。
7.1 检查文件是否成功打开
在进行任何读写操作前,检查文件是否成功打开是一个好习惯。
示例:
1 |
|
7.2 逐行读取 vs 逐词读取
- 逐行读取:使用
std::getline逐行读取文件内容。 - 逐词读取:使用
>>运算符逐词读取文件内容。
示例:
1 |
|
输出(假设 output.txt 内容如下):
1 | 这是第一行。 |
具体输出:
1 | 逐词读取文件内容: |
解释:
infile >> word会根据空格、换行符等分隔符逐个读取单词。
7.3 错误处理
在文件操作中,可能会遇到各种错误情况,如文件不存在、权限不足等。通过流的状态标志可以进行相应的错误处理。
示例:
1 |
|
解释:
- 如果文件
nonexistent.txt不存在,程序会输出错误消息并退出。
7.4 追加模式
使用 std::ios::app 可以以追加模式打开文件,数据将被添加到文件末尾,而不是覆盖原有内容。
示例:
1 |
|
解释:
- 每次运行该程序,新的日志记录都会被添加到
log.txt的末尾,而不会删除之前的内容。
7.5 读写模式中的其他标志
- **
std::ios::binary**:以二进制模式打开文件。 - **
std::ios::trunc**:如果文件已存在,打开时会清空文件内容。 - **
std::ios::ate**:打开文件并将文件指针移动到文件末尾,允许在文件末尾追加。
示例:
1 |
|
输出:
1 | 读取的数字是:12345 |
解释:
- 使用
std::ios::binary以二进制模式打开文件。 write和read方法用于写入和读取二进制数据。reinterpret_cast<char*>将数据类型转换为字节流。
注意:
- 二进制模式适用于非文本数据,可以提高读写效率,但可读性较差。
- 在不同操作系统之间传输二进制文件时,需要注意字节序(Endianess)的问题。
7.6 实际应用示例
示例说明:读取一个文本文件,统计单词出现的次数,并将结果写入另一个文件。
1 |
|
解释:
- 读取
input.txt文件中的每个单词,并使用std::map统计每个单词出现的次数。 - 将统计结果写入
word_count.txt文件中。 - 这是一个简单的文本分析工具,可以进一步扩展功能,如忽略大小写、去除标点符号等。