C++ 流的操作 | 初识IO类、文件流、string流的使用
文章目錄
- 前言
- IO頭文件
- iostream
- fstream
- sstream
- 流的使用
- 不能拷貝或?qū)?IO對象 賦值
- 條件狀態(tài)與 iostate 類型
- 輸出緩沖區(qū)
- 文件流
- fstream類型
- 文件模式
- string流
- istringstream
- ostringstream
前言
我們在使用 C++ 的過程中,總避免不了 IO操作,比如經(jīng)常用到的一些 IO庫設(shè)施:
- istream:(輸入流)類型,提供輸入操作。
- ostream:(輸出流)類型,提供輸出操作。
- cin:一個 istream 對象,從標(biāo)準(zhǔn)輸入讀取數(shù)據(jù)。
- cout:一個 ostream 對象,向標(biāo)準(zhǔn)輸出寫入數(shù)據(jù)。
- cerr:一個 ostream 對象,通常用于輸出程序錯誤消息,寫入到標(biāo)準(zhǔn)錯誤。
- >>運算符:用來從一個 istream 對象讀取輸入數(shù)據(jù)。
- <<運算符:用來向一個 ostream 對象寫入輸出數(shù)據(jù)。
- getline函數(shù):從一個給定的 istream 讀取一行數(shù)據(jù),存入一個給定的 string 對象中。
但實際上可能僅僅是懵懵懂懂在使用,如果不深入了解的話,實際上這樣的使用是淺薄的。
IO頭文件
iostream
定義了用于讀寫流的基本類型。
- istream,wistream 從流讀取數(shù)據(jù)
- ostream,wostream 向流寫入數(shù)據(jù)
- iostream,wiostream 讀寫流
fstream
定義了讀寫命名文件的類型。
- ifstream,wifstream 從文件讀取數(shù)據(jù)
- ofstream,wofstream 向文件寫入數(shù)據(jù)
- fstream,wfstream 讀寫文件
sstream
定義了讀寫內(nèi)存string對象的類型。
- istringstream,wistringstream 從 string 讀取數(shù)據(jù)
- ostringstream,wostringstream 向 string 寫入數(shù)據(jù)
- stringstream,wstringstream 讀寫 string
流的使用
標(biāo)準(zhǔn)庫通過繼承使我們忽略不同類型流之間的差異。舉例來說,類型 ifstream 和 istringstream 都繼承自 istream。因此,我們?nèi)绾问褂?cin ,就可以同樣地使用這些類型的對象。
不能拷貝或?qū)?IO對象 賦值
ofstream out1, out2; out1 = out2; // error:不能對流對象賦值 ofstream printf(ofstream); // error: 不能初始化ofstream參數(shù) out2 = printf(out2); // error: 不能拷貝流對象- 由于不能拷貝IO對象,因此我們也不能將形參或返回類型設(shè)置為流類型。
- 進(jìn)行IO操作的函數(shù)通常以引用方式傳遞和返回流。讀寫一個IO對象會改變其狀態(tài),因此傳遞和返回的引用不能是const的。
條件狀態(tài)與 iostate 類型
IO操作使用不當(dāng)?shù)脑挄l(fā)生錯誤,而如果是發(fā)生在系統(tǒng)深處的錯誤,那么就超出了應(yīng)用程序可以修正的范圍。但也有一些錯誤是可以恢復(fù)的,IO類也提供了一些函數(shù)和標(biāo)志來訪問、操縱流的條件狀態(tài)。
下面對表中的四個條件位作進(jìn)一步介紹。
iostate 類型
IO庫定義了一個與機(jī)器無關(guān)的 iostate 類型,它提供了表達(dá)流狀態(tài)功能。
IO庫定義了 4個 iostate類型 的 constexpr 值(常量表達(dá)式),表示特定的位模式:
- badbit: 表示系統(tǒng)級錯誤,如不可恢復(fù)的讀寫錯誤。通常情況下,一旦 badbit 被置位,流就無法再使用了。
- failbit: 在發(fā)生可恢復(fù)錯誤后被置位,如期望讀取數(shù)值卻讀出一個字符等錯誤。這種問題通常是可以修正的,流還可以繼續(xù)使用。
- eofbit: 如果到達(dá)文件結(jié)束位置,連同 failbit 一起被置位。
- goodbit: 值為 0 時,表示流未發(fā)生錯誤。
對他們進(jìn)行一個簡單的使用:
auto old_state = cin.rdstate(); // 返回流cin的當(dāng)前狀態(tài),返回值類型為 strm::iostate cin.clear(); // 將cin所有條件位復(fù)位,換言之,使cin有效 // clear重載版本允許有參數(shù),接受一個iostate值,表示流的新狀態(tài) cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit); // 先用rdstate讀出當(dāng)前條件狀態(tài),再將failbit和badbit復(fù)位生成新狀態(tài)。 process_input(cin); // 使用cin cin.setstate(old_state); // 將cin置為原有狀態(tài)輸出緩沖區(qū)
以前對于輸出緩沖區(qū)是沒什么概念的……直到在做美團(tuán)往年筆試題的時候,有道編程題如果用 endl 作為換行會報超時,原因是 endl 頻繁刷新輸出緩沖區(qū),因此需要用 '\n' 。
操作系統(tǒng)的 IO操作 是很耗時的,緩沖機(jī)制使操作系統(tǒng)將程序的多個輸出操作組合成單一的系統(tǒng)級寫操作(寫到顯示設(shè)備上),對性能的提升是巨大的。
導(dǎo)致緩沖刷新(數(shù)據(jù)真正寫到輸出設(shè)備或文件)的原因有很多:
關(guān)于第三點,共有三種操作符可用來刷新緩沖:
- endl: 換行并刷新緩沖區(qū)
- flush: 僅刷新緩沖區(qū),但不輸出任何額外字符
- ends: 向緩沖區(qū)插入一個空字符然后刷新緩沖區(qū)
關(guān)于第四點:
- unitbuf操縱符: 每次寫操作之后都進(jìn)行一次 flush 操作
- nounitbuf操縱符: 重置流,使其恢復(fù)默認(rèn)的緩沖區(qū)刷新機(jī)制
值得一提的是,如果程序崩潰,輸出緩沖區(qū)不會被刷新。
關(guān)于第五點,C++提供了 tie函數(shù) 來查看當(dāng)前對象關(guān)聯(lián)的輸入輸出流,tie 有兩個重載版本:
- 無參數(shù)版本: 返回指向輸出流的指針。當(dāng)前對象若關(guān)聯(lián)了一個輸出流,則返回指向該流的指針;若未關(guān)聯(lián)流,則返回空指針。
- 參數(shù)為一個指向 ostream 的指針: 將當(dāng)前對象關(guān)聯(lián)到此 ostream 。
每個流同時最多關(guān)聯(lián)到一個流,但多個流可以同時關(guān)聯(lián)到同一個 ostream 。
示例:
cin.tie(&cout); // 標(biāo)準(zhǔn)庫默認(rèn)將 cin 和 cout 關(guān)聯(lián)在一起 cin.tie() = cin.tie(nullptr); // 通過傳遞空指針,讓 cin 不再與其他流關(guān)聯(lián)文件流
fstream類型
除了繼承自 iostream類型 的行為外,fstream類型 還增加了一些新的成員來管理與流關(guān)聯(lián)的文件。
open函數(shù)
fstrm(s) 之所以能在調(diào)用時打開文件s,是因為自動調(diào)用了 open函數(shù) ,等價于:
ifstream in; // 輸入文件流未與任何文件關(guān)聯(lián) in.open(ifile); // 打開指定文件,并與in綁定對一個已經(jīng)打開的文件流調(diào)用 open 會失敗,此時 failbit 會被置位,隨后使用文件流的操作都會失敗。因此,調(diào)用 open 后檢測是否成功是個好習(xí)慣:
if(in) // 成功 else // 不成功如果想要將文件流關(guān)聯(lián)到另一個文件,必須先關(guān)閉已關(guān)聯(lián)的文件:
in.cloes(); in.open(ifile);open 成功調(diào)用會將 good() 設(shè)為 true。
close函數(shù)
當(dāng)一個 fstream對象 被銷毀時,close 會自動被調(diào)用。
文件模式
每個文件流類型都定義了一個默認(rèn)的文件模式,當(dāng)我們未指定文件模式時,就使用此默認(rèn)模式。
- 與 ifstream關(guān)聯(lián) 的文件默認(rèn)以 in模式 打開;
- 與 ofstream關(guān)聯(lián) 的文件默認(rèn)以 out模式 打開;
- 與 fstream關(guān)聯(lián) 的文件默認(rèn)以 in和out模式 打開。
雖然不論是調(diào)用 open 打開文件,還是 fstrm(s) 這樣隱式打開文件,都可以指定文件模式,但指定文件模式有如下限制:
- 為了保留以 out 模式打開的文件的內(nèi)容,我們必須同時指定 app 模式,這樣只會將數(shù)據(jù)追加寫到文件末尾;
- 或者同時指定 in 模式,即打開文件同時進(jìn)行讀寫操作。
關(guān)于第五點,舉例詳細(xì)講一下:
/*截斷*/ ofstream out1("file1"); // 隱含以out模式打開文件并截斷文件 ofstream out2("file1", ofstream::out); // 隱含地截斷文件 ofstream out3("file1", ofstream::out | ofstream::trunc); // 顯式實現(xiàn)out模式打開文件并截斷/*app模式保留文件內(nèi)容*/ ofstream app1("file2", ofstream:app); // 隱含out模式 ofstream app2("file2", ofstream:out | ofstream:app);string流
同樣的,除了繼承自 iostream 的操作,sstream 也增加了獨有的操作。
istringstream
我們經(jīng)常會碰到處理整行字符串的問題,比如:比較版本號
用雙指針截取字符串當(dāng)然是一種方法,但是使用 istringstream 這個標(biāo)準(zhǔn)庫提供的利器會更加方便。當(dāng)然,兩種方法的時間、空間復(fù)雜度是一樣的。
下面通過分析 istringstream 的使用來進(jìn)一步理解如何用:
class Solution { public:int compareVersion(string version1, string version2) {istringstream in1(version1); // 將文本version1與輸入流in1綁定istringstream in2(version2);int a, b;char c;while(in1.good() || in2.good()){in1 >> a; // 從in1中讀取int數(shù)據(jù)到a中,遇到空白符or非int數(shù)據(jù)停下in2 >> b;if(a > b) return 1;if(a < b) return -1;a = b = 0;in1 >> c; // 從in1中讀取char類型數(shù)據(jù)到c中,遇到空白符or非char數(shù)據(jù)停下in2 >> c;}return 0;} };再比如,有這樣的輸入,人名和他們的常用密碼,一個人可能有多種常用密碼:
cmy 12345 22345 lx 6644 lhy 6633 1221 5665那么我們可以這樣處理:
struct per_pw{string name;vector<string> pw; } string s, word; // s暫存來自輸入的一行文本 vector<per_pw> people; while(getline(cin, s)){ // 處理一行文本,也就是一個人的信息per_pw pp;istringstream in(s); // 將in綁定到剛讀取的sin >> pp.name; // 讀取名字while(in >> word) // 讀取密碼pp.pw.push_back(word); // 密碼存入pp的pw數(shù)組中people.push_back(pp); // 將這個人的信息保存在people數(shù)組中 }ostringstream
當(dāng)我們希望將多個輸出最后一起打印時,ostringstream 是很有用的。舉個簡單的例子:
ostringstream out; // 創(chuàng)建一個未綁定的輸出流 vector<string> vs = {"cmy", "lx", "lhy"}; for (string s : vs) {out << s << " "; } cout << out.str() << endl; // str():返回out保存的string的拷貝,也就是將out轉(zhuǎn)換為string類型。我們使用標(biāo)準(zhǔn)的輸出運算符<<向 out 寫入數(shù)據(jù),有趣的是,這些寫入操作實際上轉(zhuǎn)換為 string 操作,向 out 中的 string 對象添加字符。
總結(jié)
以上是生活随笔為你收集整理的C++ 流的操作 | 初识IO类、文件流、string流的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 经济滞涨的可怕之处 经济滞涨的后果
- 下一篇: 信用卡逾期1万会上门讨债吗?这里有几个应