C++中的IO库(一)

时间: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()从而达到目的。



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值