新的C++标准中有三分之二的内容都是描述标准库。接下来重点学习其中几种核心库设施,这些是应该熟练掌握的。
标准库的核心是很多容器类(顺序容器和关联容器等)和一簇泛型算法(该类算法通常在顺序容器一定范围内的元素上或其他类型的序列上进行操作)。
该篇主要学习IO库。
C++语言不直接处理输入输出,而是通过一簇标准库中的IO库来处理。IO库定义了读写内置类型值的操作。
1、IO类
为了处理不同的种类的IO操作,定义了:iostream(用于读写流的基本类型)、fstream(读写命名文件的类型)、sstream(读写内存string对象的类型)。
其中后面以w开头的是宽字符版本。
IO类型间的关系
继承机制:ifstream和istringstream都是继承自istream,上述所有的IO库类型之间都存在这种继承关系。
下面介绍的标准库流特性都可以无差别地应用于普通流、文件流和string流,以及它们的宽字符版本。
1.1 IO对象无拷贝或赋值
不能拷贝或对IO对象赋值
ofstream out1,out2; out1=out2; //错误,不能对流对象赋值 ofstream print(ofstream); //错误,不能初始化ofstream参数 out2=print(out2); //错误,不能拷贝流对象
因为不能拷贝IO对象,因此不能将形参或返回类型设置为流类型。进行IO操作的函数通常以引用方式传递和返回流。读写一个IO对象会改变其状态,因此传递和返回的引用不能是const。
1.2 条件状态
IO操作可能会发生错误,IO类通过定义一些条件状态来显示IO对象的状态,使用户知道流的当前状态。
由于流操作可能发生的错误,因此,代码通常应该在使用一个流之前检查它是否处于良好状态,最简单的方法是将它当作一个条件来使用。
while(cin>>word) { ...... }
查询流的状态
有时候不仅仅需要知道流是否有效,还要知道到底是什么原因导致流失效,IO库定义了一个与机器无关的iostate类型,它提供了表达流状态的完整功能。这个类型应作为一个位集合来使用。
使用good或fail是确定流的总体状态的正确方法。上述将流作为条件使用的代码等价于!fail()。
while(cin>>word) { ...... } ================== cin >> s; while (!(cin.fail())) { }
管理条件状态
流对象的rdstate成员返回一个iostate值,对应流的当前状态。setstate操作将给定条件位置位,表示发生了对应错误。clear成员是一个重载的成员。有一个无参数的版本,清除所有错误标志位。
auto old_state=cin.rdstate(); //记住cin的当前状态 cin.clear(); //清除所有错误 process_input(cin); //使用cin cin.setstate(old_state); //将cin置为原有状态
1.3 管理输出缓冲
每个输出流都管理一个缓冲区,用来保存程序读写的数据。
刷新输出缓冲区
已经使用过操纵符endl,它完成换行并刷新缓冲区的工作。IO库还有两个类似的操纵符:flush和ends。flush刷新缓冲区,但不输出任何额外的字符;ends向缓冲区插入一个空字符,然后刷新缓冲区。
unitbuf操纵符
unitbuf每次输出操作后都刷新缓冲区。它告诉流在接下来的每次写操作之后都进行一次flush。而nounitbuf操纵符则重置流,使其恢复正常的系统管理的缓冲区刷新机制。
cout<<unitbuf; //所有输出操作后都会立即刷新缓冲区 cout<<nounitbuf; //回到正常的缓冲方式
2、文件输入输出
头文件fstream定义了三种类型来支持文件IO:ifstream、ofstream、fstream。
fstream除了继承自iostream类型的行为之外,fstream还定义了一些自己专有的操作。这是其他IO类型所没有的。
2.1 使用文件流对象
用fstream代替iostream&
在使用iostream的地方,可以用fstream代替调用,因为fstream是从iostream继承来的。
成员函数open和close
可以先定义一个空文件流对象,然后用open将其与文件关联起来。
如果调用open失败,则failbit会被置位,因此进行open是否成功的检测是一个好的习惯。
ofstream out; out.open("1.txt"); if(out) .......
将文件流对象绑定到另一个文件之前,需要先close已经关联的文件,然后再关联新的文件。
自动构造和析构
当一个fstream对象被销毁时,close会自动被调用。
2.2 文件模式
每个流都有一个关联的文件模式,用来指出如何使用文件。
指定文件模式有如下限制
- 只可以对ofstream和fstream对象设定out模式
- 只可以对ifstream和fstream对象设定in模式
- 只有当out也被设定时才可设定trunc模式
- 只要trunc没被设定,就可以设定app模式。在app模式下,即使没有显式指定out模式,文件也总是以输出方式被打开
- ate和binary模式可用于任何类型的文件流对象,且可以与其他任何文件模式组合使用
每个文件流类型都定义了一个默认的文件模式,ifstream是in,ofstream是out,fstream是in和out
以out模式打开文件会丢弃已有数据
默认情况下,打开一个ofstream时,文件的内容会被丢弃。阻止一个ofstream清空给定文件内容的方法是同时指定app模式。
ofstream app("file",ofstream::app); ofstream app2("file",ofstream::out | ofstream::app);
每次调用open时都会确定文件模式
ofstream out; out.open("file1"); //模式隐含设置为输出和截断 out.close(); out.open("file2",ofstream::app); //模式为输出和追加 out.close();
通常情况下,out模式意味着同时使用trunc模式,因此,file1的文件的内动将被清空。
每次打开文件时,都要设置文件模式,可能是显式地设置,也可能是隐式地设置,当程序未指定模式时,就使用默认值。
3、string流
sstream头文件定义了三个类型来支持内存IO,这些类型可以向string读写数据,string像是一个IO流一样。
- istringstream
- ostringstream
- stringstream
上述三种都继承自iostream。同样的,除了继承来的操作,其也定义了自己特有的操作。