# 一、概述

C++ 中的流(streams)是用于处理输入和输出的抽象概念,主要用于与设备(如键盘、屏幕、文件等)进行数据交互。流在 C++ 中主要由以下几个方面组成:

# 1. 流的类型

C++ 中有两种主要的流类型:

  • 输入流(Input Stream):用于从输入设备读取数据。最常用的输入流是 std::cin ,它用于从标准输入(通常是键盘)读取数据。

  • 输出流(Output Stream):用于将数据输出到输出设备。最常用的输出流是 std::cout ,它用于将数据输出到标准输出(通常是屏幕)。

# 2. 流的类

在 C++ 中,流是通过类来实现的,主要有以下几个类:

  • std::istream :用于输入流的基类,提供了基本的输入操作。
  • std::ostream :用于输出流的基类,提供了基本的输出操作。
  • std::fstream :用于文件的输入输出操作,既可以读取文件也可以写入文件。

# 3. 基本操作

  • 输入操作
    使用 std::cin 读取数据可以用 >> 操作符。例如:

    1
    2
    3
    int x;
    std::cout << "请输入一个整数:";
    std::cin >> x;

  • 输出操作
    使用 std::cout 输出数据可以用 << 操作符。例如:

    1
    std::cout << "你输入的整数是:" << x << std::endl;

# 4. 文件流

对于文件的读写,使用 std::ifstreamstd::ofstream 类:

  • 读取文件

    1
    2
    3
    4
    5
    6
    7
    std::ifstream infile("data.txt");
    if(infile.is_open()) {
    int value;
    while(infile >> value) {
    std::cout << value << std::endl;
    } infile.close();
    }

  • 写入文件

    1
    2
    3
    4
    5
    std::ofstream outfile("output.txt");
    if(outfile.is_open()) {
    outfile << "Hello, World!" << std::endl;
    outfile.close();
    }

# 5. 流的格式化

C++ 的流可以进行格式化操作,例如控制输出的精度、宽度等:

  • 设置精度

    1
    2
    std::cout.precision(2); // 设置小数精度为2
    std::cout << std::fixed << 3.14159 << std::endl; // 输出为3.14

  • 设置宽度

    1
    std::cout << std::setw(10) << std::setfill('0') << x << std::endl; // 设置输出宽度为10,使用0填充

更多细节,见下文:输入输出操纵符

# 6. 错误处理

流还提供了错误处理的功能,可以通过检查流的状态来确定操作是否成功:

1
2
3
if(std::cin.fail()) {
std::cout << "输入错误!" << std::endl;
}

# 7. 流的优先级

C++ 中的流操作优先级比较高,可以方便地进行链式操作。例如:

1
2
3
std::cout << "请输入一个数字:" << std::endl;
std::cin >> x;
std::cout << "你输入的数字是:" << x << std::endl;

在 C++ 中,流的优先级指的是可以将多个流操作(输入或输出)串联在一起进行的能力。这种方式使得代码更加简洁和易读。

# 二、字符串流

# 1. 什么是 std::stringstream

std::stringstream 是 C++ 标准库中的一个类,位于 <sstream> 头文件中。它允许程序员在内存中创建一个字符串流,支持输入和输出操作。简单来说, std::stringstream 结合了 std::istringstreamstd::ostringstream 的功能,既可以从字符串中读取数据,也可以向字符串中写入数据。

# 2. 基本特性

  • 输入输出:可以使用 >><< 操作符进行输入和输出操作。
  • 字符串存储:可以在内存中动态创建和操作字符串。
  • 格式化能力:可以像其他流一样对数据进行格式化。

# 3. 主要方法

  • 构造函数

    1
    2
    std::stringstream ss; // 默认构造函数
    std::stringstream ss("初始字符串"); // 使用字符串初始化

  • 写入数据
    使用 << 操作符将数据写入流:

    1
    ss << "Hello, " << 42 << "!";

  • 读取数据
    使用 >> 操作符从流中读取数据:

    1
    2
    3
    std::string str;
    int num;
    ss >> str >> num; // 根据空格分隔读取

  • 获取字符串
    使用 .str() 方法获取流中的完整字符串:

    1
    std::string result = ss.str();

  • 清空流
    可以使用 .clear() 方法清空流的状态,并用 .str("") 清空内容:

    1
    2
    ss.str(""); // 清空字符串内容
    ss.clear(); // 清空流状态

注意! 当我们要清空 stringstream 时,不应该调用  clear() ,而是调用  str("")

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <sstream>
using namespace std;

int main()
{
stringstream ss;
ss.write("hello world", 11);
cout << ss.str() << endl;
ss.str("");
cout << ss.str() << endl;
return 0;
}

clear 只是清空流的状态,并不是清空其内容。

# 4. 应用场景

  • 格式化输出:当需要将多个数据格式化为一个字符串时, std::stringstream 非常有用。
  • 数据解析:从格式化的字符串中提取数据,特别适合处理 CSV、JSON 等格式。
  • 临时存储:在不想直接创建临时字符串的情况下,可以使用 std::stringstream 进行中间处理。

# 5. 性能

由于 std::stringstream 在内存中操作字符串,性能通常比频繁的字符串拼接更高效,尤其是在处理大量数据时。

# 三、其他

# i、Input/output manipulators

在 C++ 中,输入 / 输出操纵符(Input/Output Manipulators)是用于格式化输入和输出的特殊函数。它们可以被应用于流操作,以改变输出的格式、对齐方式、小数位数等。通过使用这些操纵符,你可以更精确地控制输出的外观,使得代码更易于阅读和维护。

以下是一些常用的输入 / 输出操纵符:

std::setw(int n)
设置字段宽度。
用于指定下一个输出项的字段宽度为 n 个字符,如果输出的项长度不足 n ,则会使用空格填充。

1
2
3
4
5
6
7
8
#include <iostream>
#include <iomanip>

int main() {
int number = 42;
std::cout << std::setw(10) << number << std::endl; // 输出项宽度为 10
return 0;
}

std::setfill(char c)
设置填充字符。
用于指定填充字符,该字符会被用来填充字段宽度之外的空白位置。

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <iomanip>

int main() {
int number = 42;
std::cout << std::setfill('*') << std::setw(10) << number << std::endl; // 使用 '*' 填充
return 0;
}

# $ ./test.exe
# ********42

这个函数可用于 0 的填充,如 16 进制的前置零:0x0A、0x03

std::setprecision(int n)
设置小数位数。
用于控制浮点数的输出精度,指定小数点后的位数为 n

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <iomanip>

int main() {
double value = 3.14159;
std::cout << std::setprecision(3) << value << std::endl; // 输出三位小数
return 0;
}

# $ ./test.exe
# 3.14

std::fixedstd::scientific
设置浮点数输出格式为固定小数点和科学计数法。
可以与 std::setprecision 一起使用,后者用于控制精度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <iomanip>

int main() {
double value = 12345.6789;
std::cout << std::fixed << std::setprecision(2) << value << std::endl; // 固定小数点输出
std::cout << std::scientific << std::setprecision(2) << value << std::endl; // 科学计数法输出
return 0;
}


# $ ./test.exe
# 12345.68
# 1.23e+04

std::hexstd::octstd::dec
用于设置整数的输出进制,分别为十六进制、八进制和十进制。

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <iomanip>

int main() {
int number = 255;
std::cout << std::hex << number << std::endl; // 十六进制输出
std::cout << std::oct << number << std::endl; // 八进制输出
std::cout << std::dec << number << std::endl; // 十进制输出
return 0;
}

另外,还有一些实用的操纵符:

1
2
3
4
5
6
7
8
9
# 将布尔值用 truefalse 打印
std::boolalpha
std::noboolalpha
# 是否跳过前导空格:仅仅作用于输入流,如 std::cin
std::skipws
std::noskipws
# 是否大写:仅仅作用于浮点数和十六进制整数输出中使用大写字符。
std::uppercase
std::nouppercase

# i、cin.ignore()

ignore()  是 istream 类的成员函数,它的原型是:

1
istream & ignore(int n = 1, int delim = EOF);

此函数的作用是跳过输入流中的 n 个字符,或跳过字符 delim 及其之前的所有字符 —— 哪个条件先满足就按哪个执行。两个参数都有默认值,因此  cin.ignore()  就等效于  cin.ignore(1, EOF) , 即跳过一个字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

int main()
{
string str;
cout << "Input: ";
//test input: helloworldnicetomeetyou
cin.ignore(5);
cin.ignore(3, 'o');
cin.ignore(8, 'o');
//多个 ignore 执行,则效果依次叠加
cin >> str;
cout << "Output: " << str << endl;

return 0;
}

通过该函数,能够过滤掉一些冗余信息,便于提取我们想要的信息。

更新于

请我喝杯咖啡吧~

Rick 微信支付

微信支付

Rick 支付宝

支付宝