Chapter 9 Streams¶
Why streams?
早期 C 使用 printf / scanf,C++ 引入 streams,但 C 风格 I/O 仍然可以继续使用。
- 优点:更好的类型安全、可扩展、更符合面向对象风格
- 缺点:语法更啰嗦、有时可能更慢(可以关闭同步以提速
cppstd::ios::sync_with_stdio(false);)
把 C 代码改成 C++ 时,I/O 不一定要强行重写,原有 stdio 通常可以先保留,只有当需要类型安全、自定义输入输出或统一流接口时,才优先切到 streams。
1 Basic¶
流(Stream)是面向设备的统一逻辑接口,是一维、单向的,文件流可支持随机访问,但 cin/cout 一般不行。
| 类型 | 输入 | 输出 | 头文件 |
|---|---|---|---|
| Generic | istream |
ostream |
<iostream> |
| File | ifstream |
ofstream |
<fstream> |
| C string(legacy) | istrstream |
ostrstream |
<strstream> |
| C++ string | istringstream |
ostringstream |
<sstream> |
| 流操作 | 说明 |
|---|---|
| Extractor(提取器) | 从流中读数据,重载 >> |
| Inserter(插入器) | 向流中写数据,重载 << |
| Manipulator(流操纵符) | 修改流状态,无须重载 |
- 文本流(Text streams):处理 ASCII 文本,可能做字符转换(例如换行转换),典型对象包括文件、字符缓冲区
- 二进制流(Binary streams):处理原始二进制数据,不做文本转换
| 标准流对象 | 说明 |
|---|---|
cin |
标准输入 |
cout |
标准输出 |
cerr |
无缓冲错误输出 |
clog |
有缓冲错误输出 |
示例
#include <iostream>
int i;
float f;
char c;
char buffer[80];
cin >> c; // 读一个字符
cin >> i; // 读一个整数,跳过前导空白
cin >> f >> buffer;
2 Input and Extractors¶
- 预定义提取器(Predefined extractors):
istream >> lvalue,支持多种基础类型与字符串、指针等

- 默认情况下,提取器通常会跳过前导空白符
- 流提取运算符:必须是二参数自由函数,第一个参数是
istream&,第二个参数是待写入对象的引用,返回istream&以支持链式调用(cin >> a >> b >> c;等价于((cin >> a) >> b) >> c;)
示例
istream& operator>>(istream& is, T& obj) {
// 读取 obj
return is;
}
int get():取下一个字符,失败返回EOF
示例
int ch;
while ((ch = cin.get()) != EOF)
cout.put(ch);
istream& get(char& ch):把下一个字符写入参数get(char* buf, int limit, char delim='\n'):最多读limit个字符或到分隔符,会补'\0',不消费分隔符getline(char* buf, int limit, char delim='\n'):最多读limit个字符或到分隔符,会补'\0',会消费分隔符ignore(int limit=1, int delim=EOF):跳过字符直到计数耗尽或遇到分隔符gcount():返回上一次读取的字符数putback(char c):把一个字符放回流中peek():查看下一个字符但不消耗
3 Output and Inserters¶
- 预定义插入器(Predefined inserters):
ostream << expression,支持多种基础类型与字符串、指针等 - 自定义输出运算符:必须是二参数自由函数,第一个参数是
ostream&,第二个参数通常是const T&,返回ostream&以支持链式调用(cout << a << b << c;等价于((cout << a) << b) << c;)
示例
ostream& operator<<(ostream& os, const T& obj) {
// 输出 obj
return os;
}
put(char):打印单个字符
示例
cout.put('a'); // 向标准输出流(控制台)输出字符 a
cerr.put('!'); // 向标准错误流输出字符 !
flush():强制刷新输出流的缓冲区,让内容立即输出到设备(如控制台),而非暂存于缓冲区
示例
// 先向输出流写入提示语,再通过 flush() 强制刷新,确保提示语立刻显示在屏幕上
cout << "Enter a number";
cout.flush();
4 Manipulators¶
- 操纵器(manipulator):用来修改流状态,通常需包含
<iomanip>,很多效果会在后续输出中持续生效
示例
#include <iostream>
#include <iomanip>
int main() {
cout << setprecision(2) << 1230.243 << endl;
cout << setw(20) << "OK!";
}
输出为:
1.2e+03
OK!
输入时也可搭配操纵器
int n;
cin >> hex >> n; // 后续按十六进制读取

自定义 manipulator
ostream& tab(ostream& out) {
return out << '\t';
}
cout << "Hello" << tab << "World!" << endl;
Stream Flags
- 操纵器:
setiosflags(flags)和resetiosflags(flags) - 成员函数:
setf(flags)和unsetf(flags)
