IO标准库——①IO类概述

来源:互联网 发布:谁有淘宝白菜群 编辑:程序博客网 时间:2024/06/06 16:55

C++语言不直接处理输入输出,而是通过一族在标准库中的类型来处理IO。

这些类型支持从设备读取数据、向设备写入数据的IO操作,设备可以是文件、控制台窗口以及内存。

本文首先介绍IO库中常用的基本概念。

IO类型间的关系

为了支持不同种类的IO处理操作,在istream和ostream的基础上,标准库定义了其他一些IO类型:

  • 头文件iostream定义了用于读写流的基本类型。
  • 头文件fstream定义了读写命名文件的类型。
  • 头文件sstream定义了读写内存string对象的类型。

这些IO类型之间的关系如下图所示:

这里写图片描述

因为继承机制使我们可以声明一个特定的类继承自另一个类,我们通常可以将一个派生类对象当做其基类对象来使用,所以:

  • 类型ifstream和istringstream都继承自istream,因此,我们可以像使用istream对象一样使用ifstream和istringstream对象,也就是说,我们是如何使用cin的,就可以同样的使用这些类型的对象。
  • 类型ofstream和ostringstream都继承自ostream,因此,我们可以同样地使用这些类型的对象。

标准库是我们忽略不同类型的流之间的差异, 这是通过继承机制实现的。

IO对象不能拷贝和赋值

由于IO对象是系统资源,要经过特定的函数创建或销毁,系统才能统一管理,以免造成资源冲突或是内存泄漏。

所以:

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

管理输入错误

IO操作一个与生俱来的问题是可能发生错误。

下面是一个IO错误的例子:

int ival;cin >> ival;

如果我们在标准输入上键入boo,读操作就会失败。

代码中的输入运算符期待读取一个int,但却得到一个字符b,这样,cin就进入错误状态。

一个流一旦发生错误,其上后续的IO操作都会失败。

只有当一个流处于无错状态时,我们才可以从它读取数据,向它写入数据。

由于流可能处于错误状态,因此代码通常应该在使用一个流之前检查它是否处于良好状态。

确定一个流对象的状态的最简单的方法是将它当作一个条件来使用:

int ival;while (cin >> ival){    cout << ival << endl;}

while循环检查>>表达式返回的流的状态。如果输入操作成功,流保持有效状态,则条件为真。

管理输出缓冲

每个输出流都管理一个缓冲区,用来保存程序读写的数据。

这里写图片描述

有了缓冲机制,操作系统就可以将程序的多个输出操作组合成单一的系统级写操作。

由于设备的写操作可能很耗时,允许操作系统将多个输出操作组合成单一的设备写操作可以带来很大的性能提升。

缓冲刷新是数据真正的写到输出设备或文件,导致缓冲刷新的原因有很多:

①程序正常结束导致缓冲刷新

程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行。

②缓冲区满导致缓冲刷新

缓冲区满时,需要刷新缓冲,而后新的数据才能继续写入缓冲区。

③使用操纵符显式刷新缓冲区

IO库中有三个操纵符可以显式刷新缓冲区:

  • endl结束当前行,然后将与设备关联的缓冲区中的内容刷到设备中。
  • flush刷新缓冲区,但不输出任何额外的字符。
  • ends向缓冲区插入一个空字符,然后刷新缓冲区。
cout << "hi!" << endl;cout << "hi!" << ends;cout << "hi!" << flush;

④使用unitbuf刷新缓冲区

如果想在每次输出操作后都刷新缓冲区,我们可以使用unitbuf操纵符。

unitbuf操纵符告诉流在接下来的每次写操作之后都进行一次flush操作。

nounitbuf操纵符则重置流,使其恢复使用正常的系统管理的缓冲区刷新机制。

cout << "wo shi shuai ge !" << unitbuf;cout << "wo bu shi shuai ge !" ;cout << "boring!" ;cout << "tensorflow!" ;cout << nounitbuf;

⑤关联输入流和输出流刷新缓冲区

当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。

标准库默认将cout和cin关联在一起,因此下面语句 cin >> ival; 会导致cout的缓冲区被刷新。

0 0