时间:2014.03.16
地点:基地二楼
---------------------------------------------------------------------------
一、常见IO设施概述
先来简单总结下常用的IO设施
1. istream 输入流类型,提供输入操作
2.ostream 输出流类型,提供输出操作
3. cin 一个istream对象,从标准输入读取数据
4. cout 一个ostream对象,向标准输出写入数据
5. cerr 一个ostream对象,用于输出程序错误信息,写入到标准错误
6. >>运算符,从一个istrem对象读取输入数据
7. <<运算符,向一个ostream对象写入输出数据
8. getling函数,从一个给定的istream读取一行数据,存入给定的string对象中
对于getling函数以下给出详细用法:
一般我们习惯用cin>> 这样的格式来获取输入,为什么要getline呢。原因是我们希望能在最终得到的字符串中保留输入时的空白符,这是cin>>就满足不了需求了,要用到getline。getline函数的参数是一个输入流和一个string对象。函数会从给定的输入流中读取内容,直到遇上换行符,而且换行符也会被读进来。然后把所读的内容存入string对象,但换行符不存,它实际上将会被丢弃。getline遇到换行符就结束读取操作返回结果。即便是一开始就换行也是如此。比如一开始就是个换行符的话,getline读进换行符,检测到已经是换行符了,就结束读取操作,返回内容,但由于此时什么内容也没有,因此是个空的string。
和输入运算符一样,getline也会返回流参数,我们晓得输入运算符是能作为判别条件的,所以getline的结果也一样可以。例如可用getline的结果作为条件,让程序一次输出一整行。
int main(){
string line;
while(getline(cin,line){
cout<<line<<endl;
return 0;
}
另外还要介绍的的头文件 iostream中定义的是用于读写流的基本类型——普通流,头文件fstream定义了读写命名文件的类型——文件流,头文件sstream则定义的是读写内存string对象的类型——string流。
一般情况下我们可以将一个派生类对象当做基类对象来使用。类型ifstream和istringstream对象都继承自istream,ofstream和ostringstream都继承自ostream。于是我们可以像使用istream对象一样来使用它们。比如可以对一个ifstream或istringstream对象调用getline,也可以使用>>从ifstream或istringstream对象中读取数据。
---------------------------------------------------------------------------
二、IO对象无拷贝无赋值
对IO对象进行拷贝和赋值是无意义的,所以不可以这样操作,比如:
ofstring out1,out2;
out1=out2; //错,不能对流对象赋值
ofstream print(ofstream); //错误,不能初始化ofstream参数
out2=print(out2); //不能拷贝流对象
因为不能拷贝IO对象,显然将形参或返回类型设置为流类型是不可以的,因为形参和返回设计对象的拷贝,所以,一般设计IO操作的函数以引用方式传递和返回流。另外,读写一个IO对象时会改变流的状态,所以传递和返回的引用不能是const。
---------------------------------------------------------------------------
三、条件状态
IO操作常可能发生错误,为了应对这一问题,IO类定义了一些函数和标志,根据这些流的条件状态以协助程序员处理错误。一下总结了常用的IO库条件状态的函数和标志
strm::iostate iostate是一种机器相关的类型,提供表达条件状态的完整功能
strm::badbit 用来指明流已经崩溃
strm::failbit 用来指出一个IO操作失败
strm::eofbit 指出流到了文件结束
strm::goodbit 指出流未处于错误状态,此值保证为零
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.clera(flags) 根据给定的flags标志位,将流s中对应条件状态复位,flags的类型为strm::iostate,返回void
s.setstate(flags) 根据给定的flag标志位将流s中对应条件状态置位,falgs同上
s.rdstate() 返回流s的当前的条件状态,返回值类型为strm::iostate
一个错误操作的例子:
int val;
cin>>ival;
如果我们键入 HuNan,读操作就会发生失败,因为程序期待读入一个int类型,但却得到了一个字符H,这样cin流就进入错误状态。一个流一旦发生错误,后续的IO操作都会失败。由于流可能处于错误状态,因此代码在使用一个流前一般需要检查流是否处于良好状态,最简单的办法就是将它当做一个条件来使用:
while(cin>>word)
//.....
这样while会循环检查>>表达式返回的流状态。如果输入操作成功,流保存有效状态,条件为真,继续下一次循环。
---------------------------------------------------------------------------
四、查询流的状态
当有时我们想要知道流具体状态是什么比如流为什么会失败,针对导致的原因我们可能涉及不同的处理方式,于是我们要查询流的状态了。IO库定义了一个与机器无关的iostate类型,提供了表达流状态的完整功能。该类型应该作为一个位集合来使用:
badbit 表系统级错误,如不可恢复读写错误,一旦badbit被置位,流就无法再用了
failbit IO操作失败,若被置位,如期望读取数值却读到一个字符等错误,这种问题通常可以修正,流还可以继续使用,如果到达文件结束,eofbit和failbit都会被置位。
goobit值为0,表示流未发生错误。
如果badbit failbit eofbit任意一个被置位,则检测流状态的条件会失败。
标准库中也定义了一组函数来查询这些标志位的状态。如上述总结。操作good,在所有错误位均未置位的情况下返回true,而bad fail和eof则在对应错误位被置位时返回true.,此外,在badbit被置位时,fail也返回true。即使用good和fail是确定流的总体状态的正确方法。将流当做条件使用即等价于 !fail() 。eof和bad操作只能表示特定的错误。
---------------------------------------------------------------------------
五、管理条件状态
流对象的rdstate成员函数返回一个istate值,对应流的当前状态。setstate操作则可将给定条件位置位,表示发生了对应错误。clear是一个重载成员函数,有两个版本,一个不接受任何参数,将清除所有错误标志位,即复位。执行clear()后调用good()会返回true.。一个简单的示例如下:
#include<istream>
#include<ostream>
#include<iostream>
using namespace std;
int main(){
auto old_state = cin.rdstate(); //获取当前流状态
cout << "old_state " << old_state << endl;
int a;
cin >> a; //在这里你可以输入一个非int类型的值,特意破坏流的正确性
auto current_state = cin.rdstate(); //在此获取流状态,此时显示已经不正常了
cout << "current_state " << current_state << endl;
cin.clear(); //使流所有条件状态复位,且流设为有效,这句很重要,否则后面对流的操作都会不成功,不信可试试
cin.setstate(old_state); //现在流有效了,重新使他恢复到最初始状态
auto nex_state = cin.rdstate();
cout << "new_state "<<nex_state << endl;
}
这里说明下:一定要注意当流发生错误后,如果不clear()对流进行复位,那么后面对流的操作都是不成功的。而带参数的clear()可以这样使用,让它接受一个iostate值,表示流的新状态,于是我们可以哈斯用rdstate读出的iostate值,即当前的条件状态。然后用位操作将所需要复位来生成新的状态。这里我们要用到一个公式,即
(b)& (~b)=0
现在假如我们想将failbit和badbit复位,即置0,但eofbit保持不变,可以这样做:
cin.clear(cin.rdstate()&~cin.failbit&~cin.badbit);
上面的位与操作是的表示状态的failbit 和badbit会成为0,如此得到一个新的状态,传递个clear()从而达到目的。