C++ Primer- 流的条件状态以及缓冲区管理

来源:互联网 发布:php 字符串大小写转换 编辑:程序博客网 时间:2024/05/16 09:02

IO标准库提供了一系列条件状态成员,用来标记IO对象是否处于可用状态。使用strm::iostate类型的值来表示条件状态,

这是一个跟机器有关的整型值,通过判断特定的一些位是否为1来判断流处于什么状态,有三个常量strm::badbit, strm::failbit, strm::eofbit 分别代表流被破坏,失败的IO操作和流已经到达文件尾。那么我们如何判断一个流比如说s处于什么状态呢,s.eof()若为true,表示到达文件尾,s.bad()若为ture,代表流被破坏,而 s.fail()若为true,则代表s遇到了失败的IO操作。

我们现在可以通过这三个函数来判断流的状态,那么下一步,该如何改变这个流的状态呢,有以下几个函数:

s.clear()          清除所有不可用的状态,重新使流有效

s.clear(flag)      设置流的某一个不可用状态,如badbit状态,所以flag是strm::iostate类型的

s.setstate(flag)   添加流的某一个不可用状态,如failbit状态,同样是strm::iostate类型值

s.rdstate()        返回流的当前状态,是strm::iostate类型值

 

这里我们通过一个例子来练习使用流的条件状态,题目是C++ Primer 练习8.3原题:

编写一个函数,唯一形参和返回值都是istream&类型,该函数一直读取流直到到达文件结束符,同时把读到的内容输出到标准输出中,最后,重设流使其有效并返回,通过cin为实参实现调用来测试该函数。

代码和注释如下:

/*** @file    main.cpp* @brief   编写一个函数,可以一直读取流直到文件结束 并输出* @details* @author  jason.mrbourne@gmail.com* @date    2014-5-20*/#include <iostream>#include <stdexcept>using namespace std;istream& get(istream& in){    int ival;    //遇到文件结束符前一直读入数据    while (in >> ival, !in.eof())    {        if (in.bad())   //出现系统级故障            throw runtime_error("IO stream corrupted");        if (in.fail())  //出现可恢复错误        {            cerr << "bad data, try again" << endl; //提示用户            //有一些编译器不支持in.clear(istream::failbit)语句 所以这里用in.clear()            in.clear();   //恢复流            //跳过200个字符或者遇到空格或EOF为止 因此输入时必须以空格为间隔            in.ignore(200, ' ');            continue;   //继续读入数据        }        //读入正常        cout << ival << '\t';    }    in.clear();    return in;}//在主函数中测试int main(){    int ival;    get(cin);       //这里用cin作为我们要读取的流    cin >> ival;    //重新使用恢复后的流    cout << ival << endl;    return 0;}

输出缓冲区的管理,输出缓冲区中存放着将要输出的数据,当程序结束或缓冲区满或执行一些清空缓冲区的操作时,系统会刷新缓冲区。

c++提供3个操作符用于刷新流,用法如下:

cout << “hi” << flush;      //刷新缓冲区,不添加数据

cout << “hi” << ends;       //刷新缓冲区,并在输出中插入一个null空字符

cout << “hi” << endl;       //刷新缓冲区,并在输出中插入一个换行符

 

也可以用unitbuf操纵符来实现刷新,使用unitbuf会在每一次输出后刷新缓冲区。

cout << unitbuf << “first” << “second”<< nounitbuf;

这样在输出first后缓冲区被刷新,输出second后,缓冲区再次被刷新,此时缓冲区里啥也没有。但要最后用nounitbuff把流恢复正常。

由于程序崩溃时,系统不会自动刷新缓冲区,那么此时想通过输出来找出错误发生的原因就变得异常艰难,基于这个原因,输出时应当尽可能使用endl而非’\n’。

我们还可以将输入和输出绑在一起,默认标准库是将cout与cin绑在一起,这样在读cin的时候,会导致cout的缓冲区被刷新,我们可以使用tie()来制定需要绑定的流,例如:

cin.tie(&cout);    //tie的参数为指向ostream对象的指针

ostream* old_tie = cin.tie();    //返回当前与cin绑定的流指针

cin.tie(0);        //解除cin的所有绑定,这样在读cin时,cout缓冲区将不会刷新

cin.tie(&cerr);    //将cin与cerr绑定

cin.tie(0);        //解除cin与cerr的绑定

cin.tie(old_tie);  //恢复cin与cout的绑定   


0 0