IO 类

头文件 类型
iostream istream 和 wistream 从流读取数据,ostream 和 wostream 向流写入数据,iostream 和 wiostream 读写流
fstream ifstream 和 wifstream 从流读取数据,ofstream 和 wofstream 向流写入数据,fstream 和 wfstream 读写流
sstream istringstream 和 wistringstream 从 string 读取数据,ostringstream 和 wostringstream 向 string 写入数据,stringstream 和 wstringstream 读写 string

条件状态

条件状态 说明
strm::iostate strm 是一种 IO 类,提供了表达流状态的完整功能
strm::badbit 用于指出流已崩溃
strm::failbit 用于指出一个 IO 操作失败
strm::eofbit 用于指出流到达了文件结束
strm::goodbit 用于指出流未处于错误状态,
s.eof() 若流 s 的 eofbit 置位,则返回 true
s.fail() 若流 s 的 fail 或 badbit 置位,则返回 true
s.bad() 若流 s 的 badbit 置位,则返回 true
s.good() 若流 s 处于有效状态,则返回 true
s.clear() 若流 s 中所有条件状态位复位,将流的状态位置设置为有效,返回 void
s.clear(flags) 根据给定的 flags 标志位,将流 s 中对应条件状态位复位,flags 的类型为 strm::iostate,返回 void
s.setstate(flags) 根据给定的 flags 标志位,将流 s 中对应条件状态位置位,flags 的类型为 strm::iostate,返回 void
s.rdstate() 返回流 s 的当前条件状态,返回值类型为 strm::iostate

iostate 提供了表达流状态的完整功能,这个类型应作为一个位集合来使用,IO 库定义了 4 个 iostate 类型的 constexpr 值表示特定的位模式

1
2
3
4
auto old_state = cin.rdstate(); // 记住 cin 的当前状态
cin.clear(); // 使 cin 有效
process_input(cin); // 使用 cin
cin.setsate(old_state); // 使cin 置为原有状态

clear 不接受参数的版本清除所有错误标志位,带参数的版本将所需位复位来生成新的状态,下面的代码将 failbit 和 badbit 复位,但保持 eofbit 不变

1
cin.clear(cin.rdstae() & ~cin.failbit & ~cin.badbit);

管理输出缓冲

  • 程序正常结束,作为 main 函数的 return 操作的一部分,缓冲刷新被执行
  • 缓冲区满时,需要刷新缓冲,而后新的数据才能继续写入缓冲区
  • 使用操纵符 endl 来显式刷新缓冲区
  • 在每个输出操作之后,可以用操纵符 unitbuf 设置流的内部状态,来清空缓冲区。默认情况下,对 cerr 是设置 unitbuf 的,因此写到 cerr 的内容都是立即刷新的
  • 一个输出流可能被关联到另一个流,在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。例如,默认情况下,cin 和 cerr 都关联到 cout,因此,读 cin 或写 cerr 都会导致 cout 的缓冲区被刷新

刷新输出缓冲区

1
2
3
cout << "hi!" << endl; // 输出 hi 和一个换行,然后刷新缓冲区
cout << "hi!" << flush; // 输出 hi,然后刷新缓冲区,不附加任何额外字符
cout << "hi!" << ends; // 输出 hi 和一个空字符,然后刷新缓冲区

unibuf 操纵符

1
2
cout << unitbuf; // 所有输出操作后都会立即刷新缓冲区
cout << nounitbuf; // 回到正常的缓冲方式

关联输入和输出流

当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流,标准库将 cout 和 cin 关联在一起

1
cin >> ival; // 该语句会导致 cout 的缓冲区被刷新

tie 有两个重载版本,带参数的和不带参数的。带参数的版本如果当前关联一个输出流,则返回指向这个流的指针,否则返回空指针。带参数的版本则用来关联 ostream

1
2
3
4
cin.tie(&cout); // cin 和 cout 关联
ostream *old_tie = cin.tie(nullptr); // 解除关联,获取当前的关联
cin.tie(&cerr); // 与 cerr 关联
cin.tie(old_tie); // 重新与 cout 关联

每个流同时最多关联到一个流,但多个流可以同时关联到同一个 ostream

string 流

1
2
3
4
sstream strm; // strm 是一个未绑定的 stringstream 对象,sstream 是头文件 sstream 中定义的一个类型
sstream strm(s); // strm 是一个 sstream 对象,保存 string s 的一个拷贝,此构造函数是 explicit 的
strm.str(); // 返回 strm 所保存的 string 的拷贝
strm.str(s); // 将 string s 拷贝到 strm 中,返回 void

istringstream

如果想处理 string 序列中的单词或数字,使用 istringstream 会很方便

假如有个文件,每一行是人名和他的电话号码,每个人只有一个人名但可能有多个号码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct PersonInfo {
string name;
vector<string> phones;
};

string line, word;
vector<PersonInfo> people;

while (getline(cin, line)) {
PersonInfo info;
istringstream record(line);
record >> info.name;
while (record >> word)
info.phones.push_back(word);
people.push_back(info);
}

istringstream 与每行的输入 line 绑定,然后依次读取其中的数据,数据读取完后,触发”文件读取“信号。