C++ Primer- 流的條件狀態以及緩衝區管理

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  [email protected]
* @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的綁定   


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章