8.1 IO类

  • 标准库的一些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

标准库定义了wchar_t类型的数据以支持宽字符的语言。宽字符版本的类型和函数名字以一个w开始。宽字符类型和对象与其对应的普通char版本的类型定义在一个头文件中。

  • IO类型间的关系

设备类型和字符大小都不会影响我们要执行的IO操作。标准库通过继承机制使我们忽略不同类型的流之间的差异。

8.1.1 IO对象无拷贝或赋值

  • 不能拷贝或对IO对象赋值
ofstream out1,out2;
out1 = out2; //错误:不能对流对象赋值
ofstream print(ofstream); //错误:不能初始化ofstream参数
out2 = print(out2); //错误:不能拷贝流对象

由于不能拷贝IO对象,不能将形参或者返回类型设置为流类型。进行IO操作的函数通常以引用方式传递和返回流。读写一个IO对象会改变其状态,因此传递和引用不能使const的。

8.1.2 条件状态

IO操作容易引发错误,一些是可恢复的,其他则发生在系统深处,超出了程序可以修正的范围。

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

IO错误的例子

int ival;
cin>>ival;

如果在标准输入上键入Boo,读操作就会失败。代码中的输入运算符期待一个读入一个int,但却得到了一个字符B。这样,cin就会进入错误状态。

一个流一旦发生错误,其上后续的IO操作都会失败。只有当一个流处于无错状态时,才可以从它读取数据,写入数据。由于流可能处于错误状态,因此代码通常应该在使用一个流之前检查它是否处于一个良好状态。确定流状态的最简单方法是将它当做一个条件来使用:

while(cin>>word) //ok:读操作成功

  • 查询流的状态

将流作为条件使用,只能告诉我们流是否有效,而无法告诉我们具体发生了什么。IO库定义了一个与机器无关的iostate类型,它提供了表达流状态的完整功能,这类型作为一个位集合来使用。IO库定义了四个iostate类型的constexpr值,表示特定位模式。这些值用来表示特定类型的IO条件,可以与位运算符一起使用一次性检测或设置多个标志位。

badbit表示系统级错误,如不可恢复的读写错误。通常,一旦badbit被置位,流就无法再使用了。在发生可恢复错误后,failbit被置位,如期望读取数值却读出一个字符等错误。这种问题通常是可以修正的,流还可以继续使用。如果达到文件结束位置,eofbit和failbit都会被置位。goodbit的值为0,表示流未出现错误。如果badbit、failbit、eofbit任意一个被置位,则检测流状态的条件就会失败

标准库害定义了一组函数用来查询这些标志位的状态。操作good在所有错误为均未置位时返回true,而bad、fail、eof则在对应错误位被置位时返回true。此外,在badbit被置位时,fail也会返回true。这意味着,使用good、fail是确定流的总体状态的正确方法。eof、bad操作只能表示特定的错误。

  • 管理条件状态

流对象的rdstate成员返回一个iostate值,对应流的当前状态。setstate操作将给定条件位置位,表示发生了对应错误。clear成员是一个重载的成员,它有一个不接受参数的版本,另一个版本是接受一个iostate类型的参数。clear不接受参数的复位所有错误标志位。执行clear()后,调用good会返回true。

auto old_state = cin.rdstate(); //记住cin当前状态
cin.clear(); //使cin有效
process_input(cin); //使用cin
cin.setstate(old_state); //将cin置为原有状态

带参数的clear版本接受一个iostate值,标示流的当前状态。为了复位单一的条件状态位,我们首先用rdstate读出当前条件状态,然后用位操作将所需位复位来生成新的状态。

//复位failbit、badbit,保持其他位不变
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);