《C++ Primer》筆記 第8章 IO庫

  1. iostream定義了用於讀寫流的基本類型,fstream定義了讀寫命名文件的類型,sstream定義了讀寫內存string對象的類型。
  2. 標準庫使咱們能忽略這些不一樣類型的流之間的差別,這是經過繼承機制實現的。
  3. 因爲不能拷貝IO對象,所以咱們也不能將形參或返回類型設置爲流類型。進行IO操做的函數一般以引用方式傳遞和返回流。讀寫一個IO對象會改變其狀態,所以傳遞和返回的引用不能是const的
  4. IO庫條件狀態
狀態 解釋
strm::iostate strm是一種IO類型,iostate是一種機器相關的類型,提供了表達條件狀態的完整功能。IO庫定義了4個iostate類型的constexpr值,表示特定的位模式。
strm::badbit 二進制值爲100,用來指出流已崩潰
strm::failbit 二進制值爲010,用來指出一個IO操做失敗了
strm::eofbit 二進制值爲001,用來指出流已到達了文件結束
strm::goodbit 用來指出流未處於錯誤狀態。此值保證爲零
s.eof() 若流s的eofbit置位(置1),則返回true
s.fail() 若流s的failbitbadbit置位,則返回true
s.bad() 若流s的badbit置位,則返回true
s.good() 若流s處於有效狀態,則返回true
s.clear() 將流s中全部條件狀態位復位(置0),將流的狀態設置爲有效。返回void
s.clear(flags) 根據給定的flags標誌位,將流s中對應條件狀態位置位。flags的類型爲strm::iostate。返回void
s.setstate(flags) 根據給定的flags標誌位,將流s中對應條件狀態位置位。flags的類型爲strm::iostate。返回void
s.rdstate() 返回流s的當前條件狀態,返回值類型爲strm::iostate
#include<iostream>
#include<string>
using namespace std;

istream& func(istream& is)
{
	int v;
	while (is >> v, !is.eof()) // 直到遇到文件結束符才中止讀取
	{
	
		if (is.bad())
		{
			cerr << "Bad Error!\n";
			break;
		}
		else if (is.fail())
		{
			cerr << "Wrong Data! Please try again!\n";
			is.clear();
			is.ignore(1024, '\n');
			continue;
		}
		cout << v << endl;
	}
	is.clear();
	return is;
}

int main()
{
	func(cin);
	return 0;
}
  1. badbit表示系統級錯誤,如不可恢復的讀寫錯誤。一般狀況下,一旦badbit被置位,流就沒法再使用了。在發生可恢復錯誤後,failbit被置位,如指望讀取數值卻讀出一個字符等錯誤。這種問題一般是能夠修正的,流還能夠繼續使用。若是到達文件結束位置,eofbit和failbit都會被置位。goodbit的值爲0,表示流未發生錯誤。若是badbit、failbit和eofbit任一個被置位,則檢測流狀態的條件會失敗。
  2. 在badbit被置位時,fail也會返回true。這意味着,使用good或fail是肯定流的整體狀態的正確方法。實際上,咱們將流看成條件使用的代碼就等價於!fail()。而eof和bad操做只能表示特定的錯誤。
  3. 下面的代碼將failbitbadbit復位,但保持eofbit不變:
    // 復位failbit和badbit,保持其餘標誌位不變
      cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);
    
      /*
      * clear和setstate的區別:
      * clear用實參值強制覆蓋當前流的條件狀態(不管是0仍是1)
      * setstate將實參值(置1的位)疊加到當前流的條件狀態
      */
  4. 致使緩衝刷新的緣由:
    • 程序正常結束,做爲main函數的return操做的一部分,緩衝刷新被執行。
    • 緩衝區滿時,須要刷新緩衝,然後新的數據才能繼續寫入緩衝區。
    • 咱們可使用操縱符endl來顯式刷新緩衝區
    • 在每一個輸出操做以後,咱們能夠用操縱符unitbuf設置流的內部狀態,來清空緩衝區。默認狀況下,對cerr是設置unitbuf的,所以寫到cerr的內容都是當即刷新的。
    • 一個輸出流可能被關聯到另外一個流。在這種狀況下,當讀寫被關聯的流時,關聯到的流的緩衝區會被刷新。例如,默認狀況下,cin和cerr都關聯到cout,所以,讀cin或寫cerr都會致使cout的緩衝區被刷新。
  5. 操縱符endl完成換行並刷新緩衝區的工做。flush刷新緩衝區,但不輸出任何額外的字符。ends向緩衝區插入一個空字符('\0'),而後刷新緩衝區。
  6. 若是想在每次輸出操做後都刷新緩衝區,咱們可使用unitbuf操縱符。它告訴流在接下來的每次寫操做以後都進行一次flush操做。而nounitbuf操縱符則重置流,使其恢復使用正常的系統管理的緩衝區刷新機制:
    cout << unitbuf; // 全部輸出操做後都會當即刷新緩衝區
      // 任何輸出都當即刷新,無緩衝
      cout << nounitbuf; // 回到正常的緩衝方式
  7. 若是程序異常終止,輸出緩衝區是不會被刷新的。當一個程序崩潰後,它所輸出的數據極可能停留在輸出緩衝區中等待打印。
  8. 當一個輸入流被關聯到一個輸出流時,任何試圖從輸入流讀取數據的操做都會先刷新關聯的輸出流。
  9. 交互式系統一般應該關聯輸入流和輸出流。這意味着全部輸出,包括用戶提示信息,都會在讀操做以前被打印出來。
  10. tie有兩個重載的版本:一個版本不帶參數,返回指向輸出流的指針。若是本對象當前關聯到一個輸出流,則返回的就是指向這個流的指針,若是對象未關聯到流,則返回空指針。tie的第二個版本接受一個指向ostream的指針,將本身關連到此ostream,並返回上一個綁定的輸出流指針。
  11. 咱們既能夠將一個istream對象關聯到另外一個ostream,也能夠將一個ostream關聯到另外一個ostream。每一個流同時最多關聯到一個流,但多個流能夠同時關聯到同一個ostream
    cin.tie(&cout); // 僅僅是用來展現:標準庫將cin和cout關聯在一塊兒
      // old_tie指向當前關聯到cin的流(若是有的話)
      ostream *old_tie = cin.tie(nullptr); // cin再也不與其餘流關聯
      // 將cin與cerr關聯;這不是一個好主意,由於cin應該關聯到cout
      cin.tie(&cerr); // 讀取cin會刷新cerr而不是cout
      cin.tie(old_tie); // 重建cin和cout間的正常關聯
  12. fstream特有的操做
操做 解釋
fstream fstrm; 建立一個未綁定的文件流。fstream是頭文件fstream中定義的一個類型
fstream fstrm(s); 建立一個fstream,並打開名爲s的文件。s能夠是string類型,或者是一個指向C風格字符串的指針。這些構造函數都是explicit的。默認的文件模式mode依賴於fstream的類型。
fstream fstrm(s, mode); 與前一個構造函數相似,但按指定mode打開文件
fstrm.open(s) 打開名爲s的文件,並將文件與fstrm綁定。s能夠是一個string或一個指向C風格字符串的指針。默認的文件mode依賴於fstream的類型。返回void
fstrm.close() 關閉與fstrm綁定的文件。返回void
fstrm.is_open() 返回一個bool值,指出與fstrm關聯的文件是否成功打開且還沒有關閉
  1. 在要求使用基類型對象的地方,咱們能夠用繼承類型的對象來替代。這意味着,接受一個iostream類型引用(或指針)參數的函數,能夠用一個對應的fstream(或sstream)類型來調用。
  2. 若是調用open失敗,failbit會被置位。由於調用open可能失敗,進行open是否成功的檢測一般是一個好習慣。
    if (out) // 檢查open是否成功
               // open成功,咱們可使用文件了
  3. 一旦一個文件流已經打開,它就保持與對應文件的關聯。爲了將文件流關聯到另一個文件,必須首先關閉已經關聯的文件。一旦文件成功關閉,咱們能夠打開新的文件。
    in.close() // 關閉文件
      in.open(ifile + "2"); // 打開另外一個文件
  4. 當一個fstream對象被銷燬時,close會自動被調用。
  5. 每一個流都有一個關聯的文件模式,用來指出如何使用文件。
模式 解釋
in 以讀方式打開
out 以寫方式打開
app 每次寫操做前均定位到文件末尾
ate 打開文件後當即定位到文件末尾
trunc 截斷文件
binary 以二進制方式進行IO
  1. 指定文件模式有以下限制:
    • 只能夠對ofstream或fstream對象設定out模式
    • 只能夠對ifstream或fstream對象設定in模式
    • 只有當out也被設定時纔可設定trunc模式
    • 只要trunc沒被設定,就能夠設定app模式。在app模式下,即便沒有顯式指定out模式,文件也老是以輸出方式被打開
    • 默認狀況下,即便咱們沒有指定trunc,以out模式打開的文件也會被截斷。爲了保留以out模式打開的文件的內容,咱們必須同時指定app模式,這樣只會將數據追加寫到文件末尾;或者同時指定in模式,即打開文件同時進行讀寫操做。
    • ate和binary模式可用於任何類型的文件流對象,且能夠與其餘任何文件模式組合使用。
  2. 保留被ofstream打開的文件中已有數據的惟一方法是顯式指定app或in模式
  3. 在每次打開文件時,都要設置文件模式,多是顯式地設置,也多是隱式地設置。當程序未指定模式時,就使用默認值。
  4. stringstream特有的操做
操做 解釋
sstream strm; strm是一個未綁定地stringstream對象。sstream是頭文件sstream中定義的一個類型
sstream strm(s); strm是一個sstream對象,保存string s的一個拷貝。此構造函數是explicit的
strm.str() 返回strm所保存的string的拷貝
strm.str(s) 將string s拷貝到strm中。返回void
#include<iostream>
#include<sstream>
#include<string>
#include<vector>

using namespace std;

struct PersonInfo
{
	string name;
	vector<string> phones;
};
int main()
{
	string line, word; // 分別保存來自輸入的一行和單詞
	vector<PersonInfo> people; // 保存來自輸入的全部記錄
	istringstream record;

	while (getline(cin, line))
	{
		PersonInfo info; // 建立一個保存此記錄數據的對象
		record.clear(); // 重複使用字符串流時,每次都要調用clear
		record.str(line); // 將記錄綁定到剛讀入的行
		record >> info.name; // 讀取名字
		while (record >> word) // 讀取電話號碼
			info.phones.push_back(word); // 保持它們
		people.push_back(info); // 將此記錄追加到people末尾
	}

	return 0;
}
相關文章
相關標籤/搜索