到目前为止,我们已经使用过的IO类型和对象都是操纵char数据的。默认情况下,这些对象都是关联到用户的控制台窗口的。当然,我们不能限制实际应用程序仅从控制台窗口进行I0操作,应用程序常常需要读写命名文件。而且,使用I0操作处理string中的字符会很方便。此外,应用程序还可能读写需要宽字符支持的语言。
为了支持这些不同种类的I0处理操作,在istream和ostream之外,标准库还定义了其他一些I0类型,我们之前都已经使用过了。下表列出了这些类型,分别定义在三个独立的头文件中: iostream 定义了用于读写流的基本类型,fstream 定义了读写命名文件的类型,sstream 定义了读写内存string对象的类型。
头文件 | 类型 |
---|---|
iostream | istream、wistream从流读取数据 ostream、wostream从流写入数据 iostream、wiostream 读写流 |
fstream | ifstream、wifstream 从文件读取数据 ofstream、wostream 向文件写入数据 fstream、wfstream读写文件 |
sstream | istringstream、wistringstream从string读取数据 ostringstream、wostringstream向string写入数据,stringstream、wstringstream读写string |
为了支持使用宽字符的语言,标准库定义了一组类型和对象来操纵wchar_ t类型的数据。宽字符版本的类型和函数的名字以一个w开始。例如,wcin、wcout和wcerr是分别对应cin、cout和cerr的宽字符版对象。宽字符版本的类型和对象与其对应的普通char版本的类型定义在同一个头文件中。例如,头文件fstream定义了ifstream 和wifstream类型。
IO类型之间的关系
设备类型和字符大小不会影响我们要执行的IO操作,这些操作的操作方法一致。能忽略不同流类型之间差异的原因是继承机制。
IO对象无拷贝或赋值
不能拷贝赋值,不能作为形参或返回类型。
可以通过引用方式传递或者返回流,引用不能是const类型。
访问和操纵流的条件状态
状态类型
函数 | 说明 |
---|---|
strm::iostate | 提供表达流状态完整功能,作为一个位集合使用。 |
strm::badbit | 流已崩溃,发生系统级错误,流无法被使用,badbit置位时failbit也会置位 |
strm::failbit | 一个IO操作失败,可恢复错误 |
strm::eofbit | 流达到文件结束,eofbit和failbit同时置位 |
strm::goodbit | 流未处于错误状态,此值一直为零 |
流状态查询函数
函数 | 说明 |
---|---|
s.bad() | badbit置位,返回true |
s.fail() | failbit置位,返回true |
s.eof() | eofbit置位,返回true |
s.good() | s有效状态,返回true,所有错误均未置位 |
s.rdstate() | 返回当前状态条件,返回值类型strm::iostate |
-
badbit表示发生系统级的错误,如不可恢复的读写错误。通常情况下一旦badbit被置位,流就无法再使用了。
-
failbit 表示发生可恢复的错误,如期望读取一个数值,却读出一个字符等错误。这种问题通常是可以修改的,流还可以继续使用。
-
当到达文件的结束位置时,eofbit 和 failbit 都会被置位。(类似于置为true这种感觉由原本的False置为True)
-
goodbit 被置位表示流未发生错误。如果badbit failbit 和eofbit 任何一个被置位,则检查流状态的条件会失败。
对应的bad(), fail(), eof(), good()能检查对应位是否被置位,返回1表示被置位。但是,badbit被置位时,fail()也会返回1。所以使用good()和fail()是确定流能否使用的正确方法。实际上,流当做条件使用的代码就等价于!fail()。而且eof() 和bad() 操作只能表示特定的错误。
//查询流没有出错的几种方法:
while(cin>>word){}
if(!cin.fail()){}
if(cin.good()){}
管理状态函数
函数 | 说明 |
---|---|
s.clear() | 所有条件状态位复位 |
s.clear(flags) | 流中对应条件位复位 |
s.rdstate() | 返回当前状态条件 |
管理输出缓冲
每个输出流关联一个缓冲区,保存程序读写数据。
刷新缓冲区(即数据真正写到输出设备当中)的几种情况:
- 程序正常结束,return操作结束时缓冲刷新会被执行。如果程序崩溃,缓冲区不会被刷新,数据可能会停留在输出缓冲区。
- 当缓冲区满,需要刷新缓冲。
- 使用endl显式刷新缓冲区
cout << 1 << endl; //换行并刷新缓冲区
cout << 1 << flush; //刷新缓冲区
cout << 1 << ends; //插入空字符,刷新缓冲区
- 在每个输出操作之后,可以使用操纵符unitbuf设置流的内部状态,刷新缓冲区。默认情况下,cerr内部都设置了unitbuf,所以写道cerr当中的数据都是立即刷新的。
cout<<unitbuf; //所有输出操作后会立即刷新缓冲区
cout<<noununitbuf; //回到正常缓冲方式
cerr<<1; //cerr设置为unitbuf,写到cerr的内容是立刻刷新的。
- 一个输出流关联到另外一个流。在这种情况下,当读写被关联的流的时候,关联到的流的缓冲区都会直接刷新。标准库将cin和cerr与cout关联在一起,读cin或者写cerr都会导致cout缓冲区刷新。
cin>>ival; //cout缓冲区刷新
通过tie可以将一个流与输出流进行关联,tie有两个重载的版本: 一个版本不带参数,返回指向输出流(绑定的)的指针。如果本对象当前关联到一个输出流,则返回的就是指向这个流的指针,如果对象未关联到流,则返回空指针。tie的第二个版本接受一个指向ostream的指针,将自己关联到此ostream。即x. tie (&o)将流x关联到输出流
cout << &cout << endl; //&cout
cout << cin.tie() << endl; //&cout,因为标准库默认将cout绑定给cin,所以输出的是cout的地址。
ostream* oldtie = cin.tie(nullptr);//将空绑定给cin,即解开cout绑定给cin的地址,但值得注意的是此时oldtie不是新的空地址,而是原本的cout
cout << oldtie<< endl; //&cout
cout << cin.tie() << endl; //nullptr
cin.tie(&cerr);
cout << cin.tie() << endl; //&cerr,并且此时解开cin与cout的绑定
cin.tie(oldtie);
cout << cin.tie() << endl; //&cout