1 - 初探IO库
介绍
程序的基本任务是接收输入和生成输出(IO)。在C语言中,printf()
和scanf()
可以灵活地处理IO,但它们不能很好地处理错误,处理自定义数据类型不够灵活,也不是类型安全的。
C++通过一种叫做 流(Stream) 的机制提供了更精良的IO方法,它很灵活,且面向对象,只需通过<<
或>>
运算符就能操控数据流。
组成
C++中的IO库结构如下:
C++定义了ios
这个基类,它用于定义输入输出的最基本操作,而istream
和ostream
这两个类直接继承自ios
类。
首先是用户流/控制台流:
ostream
类定义了数据从内存到输出设备流动的功能,例如cout
istream
类定义了数据从输入设备到内存流动的功能,例如cin
iostream
则综合上边的功能,定义了上边的输入输出流,我们引入这个头文件就能用用户流了:流 说明 cin
输入流,从“输入控制台”读取数据 cout
缓冲的输出流,向“输出控制台”写入数据 cerr
非缓冲的输出流,向“错误控制台”写入数据
(通常等同于“输出控制台”)clog
cerr
的缓冲版本此外,这些流还有宽字符版本(
wcin
等),适用于中文等语言。
然后是文件流:
ifstream
继承自istream
,定义了数据从磁盘到内存流动的功能。ofstream
继承自ostream
,定义了数据从内存到磁盘流动的功能。fstream
则综合上边的功能,我们引入这个头文件就能用文件流了。
最后是 字符串流,可以让我们像处理流一样处理字符串:
istringstream
继承自istream
,定义了数据从指定字符串到特定内存流动的功能。ostringstream
继承自ostream
,定义了数据从特定内存到指定字符串流动的功能。sstream
则综合上边的功能,我们引入这个头文件就能用字符串流了。
注意事项
流对象无法使用拷贝构造函数和赋值运算符
形如
istream myCin(cin);
ifstream if1, if2;
if2 = if1;
的代码将无法通过编译。因此使用流对象时 无法使用值传递,一般使用引用传递,防止内存泄漏。一般的例子就是重载<<
/>>
运算符。
流对象的状态
错误的状态
在IO操作过程中,可能会出现一些错误。有的错误可以被修复,而有的则发生在系统底层,已经超出了用户程序可以修正的范围。为了避免在IO过程中出错导致程序崩溃,我们在使用流对象时应判断流对象的状态。
可以通过rdstate()
来查看流的状态,它返回iostate
类型,在VS中是int
,用不同的位代表不同的状态。常见的状态如下:
状态 | 说明 |
---|---|
badbit | 系统级致命错误,此位为1说明流对象无法使用 |
failbit | 可修复的错误。当badbit 为1时,此位也是1 |
eofbit | 数据流当前位置为文件尾。当此位是1时,failbit 也是1 |
goodbit | 表示流对象没有任何错误 |
错误的检测
标准库还定义了一组成员函数用来查询流的状态:
.good()
:所有错误位均为0时,返回true
.bad()
,.fail()
,.eof()
:对应位为1时返回true
,用.fail()
较准确
错误的处理
一段标准的输入处理代码如下:
int item;
// 确认cin状态良好, 且没有到达文件尾
// 可用if, while
while(cin >> item, !cin.eof())
{
// cin发生致命错误, 无法修复
if (cin.bad())
{
throw runtime_error("cin is corrupted");
}
// 本次cin操作失败
else if (cin.fail())
{
// 重置cin的状态, 并丢弃输入内容
cin.clear();
cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
// 这里知道是格式错误, 直接输出错误信息
cerr << "Data format error, please try again" << endl;
}
// cin成功, 正常业务处理
cout << item << endl;
}
流对象的管理
rdstate()
:获取当前流状态setstate(flag)
:将流对象设置为想要的状态clear()
:将流状态的所有标志位复位ignore()
:获取流中的数据并丢弃它们。函数原型:
istream& ignore(streamsize n = 1, int delim = EOF)
读取到前 n 个字符或在读这 n 个字符进程中遇到 delim 字符就停止,把读取的这些东西丢掉
参考资料
- 飘零的落花 - 现代C++详解
- C++20高级编程