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的綁定