下面是IO類的繼承關系:
ifstream和istringstream都繼承自istream。因此,我們可以在傳遞istream對象的地方傳遞ifstream和istringstream。
例如:對ifstream和istringstream對象調用getline,也可以用>>從ifstream和istringstream讀取數據。
類似的ofstream和ostringstream也都繼承自ostream。
IO庫和頭文件如下:
頭文件 | 類型 |
iostream | istream,wistream從流讀取數據 ostream,wostream向流寫入數據 iostream,wiostream讀寫流 |
fstream | ifstream,wifstream從文件讀取數據 ofstream,wofstream向文件寫入數據 fstream,wfstream讀寫文件 |
sstream | istringstream,wistringstream從string讀取數據 ostringstream,wostringstream向string寫入數據 stringstream,wstringstream讀寫string
|
IO類定義了一些函數和標志,幫助我們訪問和控制流的狀態條件。
strm::iostate strm是指一種IO類型,iostate是一種機器相關的類型,提供表達條件狀態的完整功能。
strm::badbit 標志流已崩潰
strm::failbit 標志IO操作失敗了
strm::eofbit 標志達到文件結尾
strm::goodbit 流未出現錯誤狀態,此值保證為0
s.eof() 若流s的eofbit置位,則返回true
s.fail() 若流s的failbit或badbit置位,則返回true
s.bad() 若流s的badbit置位,則返回true
s.good() 若流s處於有效狀態,則返回true
s.clear() 將流的所有條件復位,狀態設置為有效,返回void
s.clear(flags) 根據flags標志位,將s中對應條件狀態復位,flags類型為strm::iostate。返回void
s.setstate(flags) 根據flags標志位,將s中對應條件狀態置位,flags類型為strm::iostate。返回void
s.rdstate() 返回流的當前條件狀態,返回類型為strm::iostate
確定流的狀態最簡單的方法是把它當做條件來使用。
例如:
while(cin >> n){//while會循環檢查輸入的狀態,成功則保持循環 ...
注意:
badbit是系統級錯誤,如不可恢復的讀寫錯誤;一般badbit置位了流就無法繼續使用。
failbit是可恢復錯誤,例如希望讀取數值,卻讀取了一個字符,這種錯誤可以修正,流還可以繼續使用。
如果達到文件結束位置,eofbit和failbit都會被置位。
googbit表示流未發生錯誤,值為0。
只要badbit、failbit、eofbit任意一個被置位,檢查流的狀態的條件會失敗。
auto oldState = cin.rdstate();//記住cin的當前狀態 cin.clear();//使cin有效 process_input(cin);//使用cin cin.setstate(oldState);//將cin的狀態還原
或者這樣使用:
cin.clear(cin.rdstate()&~cin.failbit&~cin.badbit);//只復位failbit和badbit
進行IO操作的函數通常以引用的方式傳遞和返回流。
每個輸出流都管理一個緩沖區,用來保存程序讀寫的數據。
例如:
cout << "Please input:";
字符串不一定會立刻打印出來,可能保存到緩沖區隨后打印,所以有時調試時,沒有輸出,可以看看自己刷新了緩沖區嗎?
如果程序異常終止,緩沖區是不會被刷新的,當一個程序崩潰后,它的輸出很可能停留在輸出緩沖區中等待打印。
會導致刷新緩沖區的原因:
- 程序正常結束,作為main函數的return的一部分,緩沖刷新被執行。
- 緩沖區滿,需要刷新緩沖區,而后新的數據才能寫入。
- 使用操縱符:endl來顯示刷新緩沖區。
- 每個輸出操作后,可以用操作符unitbuf設置流的內部狀態,來清空緩沖區。默認情況下,cerr是設置unitbuf的,因此寫到cerr中的數據都是立即刷新的。
- 一個輸出流被關聯到另一個流,此時,當讀寫被關聯的流時,關聯到流的緩沖區會被刷新。默認cin和cerr都關聯到cout,因此讀cin或寫cerr都會導致cout的緩沖區被刷新。
endl 換行並刷新緩沖區;
ends 插入一個空字符並刷新緩沖區;
flush 僅刷新緩沖區
使用tie函數手動關聯流:
cin.tie(&cout);//將標准庫cin和cout關聯到一起 //oldTie指向當前關聯到cin的流,如果存在的話 ostream* oldTie = cin.tie(nullptr);//cin不再與其他流關聯 cin.tie(&cerr); cin.tie(oldTie);//重建cin與cout的正常關聯
流的操作函數,以istream為例。
istream流 的操作:
1、opeartor>>操作
<<操作返回一個ostream對象的引用,所以可以連續使用
2、get( )
get( )操作:
讀取單個字符
返回一個整數
get(char&)操作:
讀取單個字符
返回一個istream對象的引用
3、getline( )
讀取一行,遇到回車鍵返回istream對象的引用
getline()操作與>>的區別:
char string1 [256],
cin.getline(string1, 256); //get a whole line, 以'\0'結尾
cin >> string1; //stop at the 1st blank space
4、read( )
read(buf, len)
返回一個istream對象的引用
對空白字符(包括'\n')照讀不誤
5、peek( ) 與 putpack()
peek:查看而不讀取
putback:將一個字符添加到流
文件流總結
需要包含的頭文件: <fstream>
fstream提供了三個類,用來實現c++對文件的操作。(文件的創建,讀寫)。
ifstream -- 從已有的文件讀
ofstream -- 向文件寫內容
fstream - 打開文件供讀寫
支持的文件類型
實際上,文件類型可以分為兩種: 文本文件和二進制文件.
文本文件保存的是可讀的字符, 而二進制文件保存的只是二進制數據。利用二進制模式,你可以操作圖像等文件。用文本模式,你只能讀寫文本文件。否則會報錯。
string流
在sstream頭文件中定義了三個類型來支持內存的IO,通過ostringstream可以向string寫入數據,通過istringstream從string讀取數據,通過stringstream向string讀寫數據
stringstream特有的操作:
sstream strm | strm是一個未綁定的stringstream對象。 |
sstream strm(s) | strm是一個stringstream對象,保存string s的拷貝。此構造函數是explicit |
strm.str() | 返回strm保存的字符串 |
strm.str(s) | 將strm保存的字符串拷貝到string s中,返回void |
當對整行文本並處理行內的某個單詞進行處理,此時可以使用string流。
istringstream將string轉換為int(通常可是直接使用to_string()和stoi(),stol(),stof(),stod()等實現string和數值類型的相互轉換)
string s = "123"; istringstream isToi(s);//將s綁定到istringstream中 int a; isToi >> a;//string輸出為int cout << a << endl;
讀取某文件中人名和電話號碼:
Morgan 1646464648 1164986463
drew 15465463132
struct PersonInfo{ string name; vector<string> phones;//多個電話號碼 } //line保存一行的信息 string line,word; vector<PersonInfo> people; //讀取一行 while(getline(cin,line)){ PersonInfo info; istringstream iss(line);//一行的字符串綁定istringstream iss >> info.name;//分離出姓名,以空格分離 while(iss >> word)info.phones.push_back(word); people.push_back(info); }
輸出上面的信息,但是不能輸出有無效號碼的人
for(const auto &info : people){ ostringstream formatted,badNums;//保存格式化信息和無效信息 for(const auto &num : info.phones){ if(!vaild(num))badNums << " " << num;//如果號碼無效則保存在內存badNums中 else formatted << " " << num;//否則保存號碼到formatted } if(badNums.str().empty())//沒有無效號碼 cout << info.name << " " << formatted.str() << endl; else cerr << "input error:" << info.name << " " << badNums.str() << endl; }