zoukankan      html  css  js  c++  java
  • 初识io流条件状态

    一  流状态
       C++中的输入输出系统负责记录每一个输入输出操作的结果信息,这些当前的状态信息被包含在io_state类型的对象中。io_state是一个枚举类型(就像open_mode一样),以下便是它包含的值。  
    eofbit 已到达文件尾 
    failbit 非致命的输入/输出错误,可挽回 
    badbit 致命的输入/输出错误,无法挽回

    这三个标志位均用一位二进制位来表示,0表示清除,1表示设置。

    对于eofbit,failbit,badbit。0表示正常,1表示被设置。

    这三个整体构成了流的状态。若三个均为0,表示流状态正常,反之,若有一个为1,流状态非正常。包括达到了文件尾,出现可恢复性错误,出现了不可恢复性的错误。

    另外还有一个标志位goodbit用来测试流状态是否正常。如果流状态正常返回true,输出1.否则输出0。
    相对应与这四个标志位有四个函数分别用来测试相应的标志位的状态。他们分别为:

    bool bad();

    bool eof();

    bool fail();

    bool good();

    看上去这四个函数的返回值是bool类型,返回值应该是true和false,也就是在我们C++里,0代表false,非0代表true,但是,在我们输出他们的结果时,得到的是0和1.不是true和false,也不是0和非0值。

    二 测试流状态。

    对于流状态的测试我们有三种方法。

    1 rdstate()函数

    我们可以用这个函数来返回当前的流状态。若我们用该函数输出当前流的状态信息,他输出的并不是一个二进制数。他输出的是一个十进制。是将二进制转换为对应的十进制后输出的。我们可以写个小程序进行一下测试,我们可以测试输入流的状态,也可以测试输出流的状态。

    如:

    #include <iostream>
    using namespace std;
    int main()
    {
        cout << "hello" << endl;
        cout << cout.rdstate() << endl;//输出当前的流状态
        if(cout.rdstate() == ios::goodbit) 
        { 
         cout<<"输出数据的类型正确,无错误!"<<endl; 
        } 
        if(cout.rdstate() == ios_base::failbit) 
        { 
         cout<<"输出数据类型错误,非致命错误,可清除输入缓冲区挽回!"<<endl;
        } 
        system("pause"); 
        return 0;
    }

    输出的当前的流状态为0.    表示当前流状态正常,那么他就和我们的if条件判断语句中的    第一个相匹配了。由此可知,rdstate() 返回的是eofbit,failbit,badbit三个标志的值,即返回的是一个strm::iostate类型。

    2 我们可以用三个标志位对应的函数来测试当前的流状态。

    如:

    #include <iostream>
    using namespace std;
    int main()
    {
     cout << "你好吗?" << endl;
        cout <<  cout.eof() << cout.fail() << cout.bad() << endl; 
        cout << cout.good() << endl;
        return 0;
    }

    输出结果为:

    你好吗?

    000

    1

    前面的000表示三个标志位对应的值,均为0,由此可知此时流状态正常,故goodbit标志位被设置。所以good()函数输出结果为1.    

    3 用流本身来测试

    如: 

    if (cin)

     while (cin >> word)

    if语句直接检查流的状态,while语句则检测表达式的返回值,即间接的检查流状态。

    我们可以用如下的函数进行测试:

    #include <iostream>
    using namespace std;
    int main()
    {
     int i;
     cin >> i;
     if (cin)
     {
      cout << "流状态正常" << i << endl;
     }
     else
     {
      cout << "流状态不正常" << i << endl;
     }
        return 0;
    }

    当我们输入的值为整型值或是能隐式转换成整型值时,当前输入流状态有效,若我们输入了字符串类型值,则会使当前输入流状态无效。

    同样我们也可以对while语句进行测试。

    #include <iostream>
    using namespace std;
    int main()
    {
     int i;
     
     while(cin >> i)
     {
      cout << "当前输入流状态有效" << endl;
     }
     cout << "输入流状态无效" << endl;
     
        return 0;
    }

    当我们输入的值为整型值或是能隐式转换成整型值时,当前输入流状态有效,若我们输入了字符串类型值,则会使当前输入流状态无效。

    三 表示流状态的四个常量

     

    标记位常量

    常量

    含义

    failbit标记位的值

    eofbit标记位的值

    badbit标记位的值

    转化为10进制

    ios::failbit

    输入(输出)流出现非致命错误,可挽回

    1

    0

    0

    4

    ios::badbit

    输入(输出)流出现致命错误,不可挽回

    0

    0

    1

    2

    ios::eofbit

    已经到达文件尾

    0

    1

    0

    1

    ios::goodbit

    流状态完全正常

    0

    0

    0

    0

     

      

    下面来解释这张表格:
    ios::failbit    ios::badbit    ios::eofbit    ios::goodbit均为常量,它们任何一个都代表了一种流状态,因此称为“输入状态标记位常量”。
    比如,ios::failbit表示的是流状态为:
     流的failbit标记位值为1,eofbit标记位值为0,badbit标记位的值为0。
             
    始终牢记:failbit,badbit,eofbit组成了流状态
            
    注意:它们不是failbit、badbit、eofbit、goodbit这四个标记位的存贮变量。
    这四个常量我认为是strm::iostate类型的常量值。
    分别对应于:
    ios::failbit 010  ---2
    ios::badbit  100  ---4
    ios::eofbit  001  ---1
    ios::goodbit 000  ---0
    我们可以用函数来测试这三个常量的值:
    #include <iostream>
    using namespace std;
    int main()
    {
        cout << ios:: failbit << endl;
        cout << ios:: badbit << endl; 
        cout << ios:: eofbit << endl;
        cout << ios:: goodbit << endl;
        return 0;
    }
    由此我们也可以得出表示流状态的三个标志位的顺序为:
    badbit,failbit,eofbit
    注意: ios::failbit ,ios::badbit,ios::eofbit,ios::goodbit均为常量值,它与当前的流状态无关。

     

    四 设置流状态

    1 设置流状态函数我们可以用setstate(flag)函数.参数为一个strm::iostate类型的值。

    如: cin.setstate(ios::eofbit);

    注意,它的目的并不是将流状态ios::eofbit替换(或覆盖)当前的输入流状态。而是仅仅的将标志位eofbit置1,其他位保持不变。

    好的,既然设置好了。我们可以来查看一下我们的流状态是否设置成功了:

    #include <iostream>
    using namespace std;
    int main()
    {
     cout << "输入流设置前的状态: " << endl;
     cout << cin.bad() << cin.fail() << cin.eof() << endl;
     cin.setstate(ios::failbit);
     cout << "输入流设置后的状态: " << endl;
     cout << cin.bad() << cin.fail() << cin.eof() << endl;
        return 0;
    }

    然后我们再进行一下测试,看一下函数setstate是否覆盖我们原来的状态:

    我们还用上一个函数,加点语句。

    #include <iostream>
    using namespace std;
    int main()
    {
     cout << "输入流设置前的状态: " << endl;
     cout << cin.bad() << cin.fail() << cin.eof() << endl;
     cin.setstate(ios::failbit);
     cout << "输入流设置第一次后的状态: " << endl;
     cout << cin.bad() << cin.fail() << cin.eof() << endl;
     cin.setstate(ios::badbit);
     cout << "输入流设置第二次后的状态: " << endl;
     cout << cin.bad() << cin.fail() << cin.eof() << endl;
        return 0;
    }

    输出结果为:

    000

    010

    110

    由此可知,函数setstate函数并没有覆盖我们原来的流状态,而是仅仅的设置了对应位。

    2 当我们设置了ios::failbit,ios::eofbit,ios::badbit流状态后,由于该三种状态为非正常状态,故设置后,对应的输入流或是输出流就处于无效状态,我们此后对于该流的任何使用均为无效,不起作用。

    不妨我们来测试一下:

    #include <iostream>
    using namespace std;
    int main()
    {
     cin.setstate(ios::failbit);
     int i;
     cin >> i;
     cout << "hello!" << endl;
        return 0;
    }

    上面这个程序不等待我们输入直接就输出了结果hello!由此可知,cin状态在设置后已处于无效状态,所有对此的操作均为视为透明的,或是无效的,直接跳过。那我们如何将流状态重置为有效呢,我认为有三种方法:

    ①:我们可以用函数clear();将流的所有状态重设为有效状态。

    ②:我们可以用函数clear(flag);

    flag 可选值有ios::badbit ios::failbit ios::eofbit,这里参数的意思是重设对应的标志位有效。

    ③:我们可以用函数setstate(ios::goodbit);重设流有效状态

    但经我在VC++ 6.0,VC++ 2008上测试后两种方法虽能成功运行,但并没起到作用。第一种方法可以。

    #include <iostream>
    using namespace std;
    int main()
    {
     cin.setstate(ios::failbit);

     cin.clear();
     int i;
     cin >> i;
     cout << "hello!" << endl;
        return 0;
    }

    输入流重为有效状态

    此题的while循环的判断调件是,只要没有遇到文件结束符,不管输入流是否有效均执行循环体。

     

    。下面我们再来整体看一个函数:

    #include <iostream>
    using namespace std;
    int main()
    {
     int i;
     while (cin >> i,!cin.eof())
     {
       try
       {
      if (cin.bad())  //出现系统故障
      {
       throw runtime_error("输入输出流出现故障");  //抛出异常
      }
       }
       catch(runtime_error err) //处理异常
       {
        cout << err.what() << endl; //输出异常原因
        cout << "try again?y/n" << endl;
        char c;
        cin >> c;
        if ('y' == c)
        {
         continue;
        }
        else
        {
         break;
        }
        
       }
      if (cin.fail()) //出现了可恢复错误
      {
       cerr << "bad data, try again";
       cin.clear(); //重置输入流有效
       cin.ignore(20,' '); //忽略20个输入字符。若不写此语句将陷入死循环。
       continue;
      }
      cout << i << " ";
     }
        return 0;
    }

    此题的while循环的判断调件是,只要没有遇到文件结束符,不管输入流是否有效均执行循环体。

     

  • 相关阅读:
    Matlab矩阵操作函数的使用(reshape,imresize,remat,permute)
    归一化数据的好处
    博客园中用markdown编辑器编辑带下标的符号
    反向传播
    稀疏表示和字典学习
    先验概率和后验概率
    Local Generic Representation for Face Recognition with Single Sample per Person (ACCV, 2014)
    删除数组
    数组扩容(指定位置)+插入最后
    创建数组的几种方式,遍历+泛型合并
  • 原文地址:https://www.cnblogs.com/txg198955/p/3999086.html
Copyright © 2011-2022 走看看