第8章:IO庫(kù)

  • #1.IO類
    • IO對(duì)象無(wú)拷貝或賦值
    • 條件狀態(tài)
    • 管理輸出緩沖
  • #2.文件輸入輸出
    • 使用文件流對(duì)象
    • 文件模式
  • #3.string流
    • 使用istringstream
    • 使用ostringstream

C++語(yǔ)言不直接處理輸入輸出,而是通過一族定義在標(biāo)準(zhǔn)庫(kù)中的類型來處理IO赋焕。

#1. IO類

iostream定義了用于讀寫流的基本類型,fstream定義了讀寫命名文件的類型,sstream定義了讀寫內(nèi)存string對(duì)象的類型芥牌。

1.1 IO對(duì)象無(wú)拷貝或賦值

ofstream out1,out2;
out1 = out2; //錯(cuò)誤:不能對(duì)流對(duì)象賦值
ofstream print(ofstream); //錯(cuò)誤:不能初始化ofstream參數(shù)
out2 = print(out2); //錯(cuò)誤:不能拷貝流對(duì)象

由于不能拷貝IO對(duì)象贫途,因此我們也不能將形參或返回類型設(shè)置為流類型坎匿。進(jìn)行IO的函數(shù)通常以引用方式傳遞和返回流。讀寫一個(gè)IO對(duì)象會(huì)改變其狀態(tài)吭净,因此傳遞和返回的引用不能是const的。

1.2 條件狀態(tài)

IO操作一個(gè)與生俱來的問題是可能發(fā)生錯(cuò)誤肴甸。一些錯(cuò)誤是可恢復(fù)的寂殉,而其他錯(cuò)誤則發(fā)生在系統(tǒng)深處,已經(jīng)超出了應(yīng)用程序可以修正的范圍原在。表中列出了IO類定義了一些函數(shù)和標(biāo)志友扰,可以幫助我們?cè)L問和操作流的條件狀態(tài)

函數(shù) 狀態(tài)
strm::iostate strm是一種IO類型庶柿。iostate 是一種機(jī)器相關(guān)類型村怪,提供了表達(dá)條件狀態(tài)的完整功能
strm::badbit strm::badbit 用來指出流已崩潰
strm::failbit strm::failbit 用來指出一個(gè)IO操作失敗了
strm::eofbit strm::eofbit 用來指出流到達(dá)了文件結(jié)束
strm::goodbit strm::goodbit 用來指出流未處于錯(cuò)誤狀態(tài)。此值保證為零浮庐。
查詢流的狀態(tài)

將流作為條件使用甚负,只能告訴我們流是否有效,而無(wú)法告訴我們具體發(fā)生了什么审残。有時(shí)我們需要知道流為什么失敗梭域。

IO庫(kù)提供了一個(gè)與機(jī)器無(wú)關(guān)的iostate類型,它提供了表達(dá)流狀態(tài)的完整功能搅轿。IO庫(kù)定義了4個(gè)iostate類型的constexpr值表示特定的位模式病涨。badbit表示系統(tǒng)級(jí)錯(cuò)誤,如不可恢復(fù)的讀寫錯(cuò)誤璧坟。在發(fā)生可恢復(fù)錯(cuò)誤后既穆,failbit被置位赎懦。如果到達(dá)文件結(jié)束位置,eofbit和failbit都會(huì)被置位循衰。goodbit的值為0铲敛,表示流未發(fā)生錯(cuò)誤。如果bidbit会钝、failbit和eofbit任一個(gè)被置位伐蒋,則檢測(cè)流狀態(tài)的條件會(huì)失敗。

管理?xiàng)l件狀態(tài)

流對(duì)象的rdstate成員返回一個(gè)iostate值迁酸,對(duì)應(yīng)流的當(dāng)前狀態(tài)先鱼。setState操作將給定條件位置位,表示發(fā)生了對(duì)應(yīng)錯(cuò)誤奸鬓。

auto old_state = cin.rdstate(); //記住cin的當(dāng)前狀態(tài)
cin.clear(); //使cin有效
process_input(cin); //使用cin
cin.setstate(old_state); //將cin置為原有狀態(tài)

1.3 管理輸出緩沖

每個(gè)輸出流都管理一個(gè)緩沖區(qū)焙畔,用來保存程序讀寫的數(shù)據(jù)。例如串远,如果執(zhí)行下面的代碼:

os << "Please enter a value";

文本可能立即打印出來宏多,也可能被操作系統(tǒng)保存在緩沖區(qū)中,隨后再打印澡罚。有了緩沖機(jī)制伸但,操作系統(tǒng)就可以將程序的多個(gè)輸出操作組合成單一的系統(tǒng)級(jí)寫操作。

導(dǎo)致緩沖刷新的原因有很多:

  • 程序正常結(jié)束留搔,作為main函數(shù)的return操作的一部分更胖,緩沖刷新被執(zhí)行。
  • 緩沖區(qū)滿時(shí)隔显,需要刷新緩沖區(qū)却妨,而后新的數(shù)據(jù)才能寫入緩沖區(qū)。
  • 我們可以使用操縱符如endl來顯示刷新緩沖區(qū)括眠。
  • 在每個(gè)輸出操作之后彪标,我們可以使用操縱符unitbuf設(shè)置流的內(nèi)部狀態(tài),來清空緩沖區(qū)掷豺。
  • 一個(gè)輸出流可能被關(guān)聯(lián)到另一個(gè)流捐下。在這種情況下,當(dāng)讀寫被關(guān)聯(lián)的流時(shí)萌业,關(guān)聯(lián)到的流的緩沖區(qū)會(huì)被刷新坷襟。
刷新輸出緩沖區(qū)

我們已經(jīng)使用過操縱符endl,它完成換行并刷新緩沖區(qū)的工作生年。

cout << "hi!" << endl; //輸出hi和一個(gè)換行婴程,然后刷新緩沖區(qū)
cout << "hi!" << flush; //輸出hi,然后刷新緩沖區(qū),不附加任何額外字符
cout << "hi!" << ends; //輸出hi和一個(gè)空字符抱婉,然后刷新緩沖區(qū)
unitbuf操作符

如果想在每次操作后都刷新緩沖區(qū)档叔,可以使用unitbuf操縱符桌粉。它告訴流接下來的每次寫操作之后都進(jìn)行一次flush操作。而nounitbuf操縱符則重置流衙四,使其恢復(fù)使用正常的系統(tǒng)管理的緩沖區(qū)刷新機(jī)制:

cout << unitbuf; //所有輸出操作后都會(huì)立即刷新緩沖區(qū)
//任何輸出都立即刷新铃肯,無(wú)緩沖
cout << nounitbuf; //回到正常的緩沖方式

==如果程序崩潰,輸出緩沖區(qū)不會(huì)被刷新传蹈。==

關(guān)聯(lián)輸入和輸出流

當(dāng)一個(gè)輸入流被關(guān)聯(lián)到一個(gè)輸出流時(shí)押逼,任何試圖從輸入流讀取數(shù)據(jù)的操作都會(huì)先刷新關(guān)聯(lián)的輸出流。標(biāo)準(zhǔn)庫(kù)將cout和cin關(guān)聯(lián)在一起惦界,因此下面語(yǔ)句:

cin >> ival;

導(dǎo)致cout緩沖區(qū)被刷新挑格。

==交互式系統(tǒng)應(yīng)該關(guān)聯(lián)輸入流和輸出流。這意味著所有輸出沾歪,包括用戶提示信息漂彤,都會(huì)在讀操作之前被打印出來。==


#2 文件輸入輸出

頭文件fstream定義了三個(gè)類型來支持文件IO:ifstream從一個(gè)給定文件讀取數(shù)據(jù)灾搏,ofstream向一個(gè)給定文件寫入數(shù)據(jù)挫望,以及fstream可以讀寫給定文件。

除了繼承自iostream類型的行為之外狂窑,fstream中定義的類型還增加了一些新的成員管理與流關(guān)聯(lián)的文件士骤。表中列出了這些操作,我們可以對(duì)fstream蕾域、ifstream和ofstream對(duì)象調(diào)用這些操作,但不能對(duì)其他IO類型調(diào)用這些操作到旦。

fstream特有的操作 含義
fstream fstrm; 創(chuàng)建一個(gè)未綁定的文件流旨巷。fstream是頭文件fstream中定義的一個(gè)類型。
fstream fstrm(s); 創(chuàng)建一個(gè)fstream添忘,并打開名為s的文件采呐。s可以是string類型,或者是一個(gè)指向C風(fēng)格字符串的指針搁骑。這些構(gòu)造函數(shù)都是explict的斧吐。默認(rèn)的文件模式依賴于fstream的類型
fstream fstrm(s,mode); 與前一個(gè)構(gòu)造函數(shù)類似,但按指定mode打開文件仲器。
fstrm.open(s) 打開名為s的文件煤率,并將文件與fstrm綁定。返回void乏冀。
fstrm.close() 關(guān)閉與fstrm綁定的文件蝶糯。返回void。
fstrm.is_open() 返回一個(gè)bool值辆沦,指出與fstrm關(guān)聯(lián)的文件是否成功打開且尚未關(guān)閉昼捍。

2.1 使用文件流對(duì)象

當(dāng)我們想要讀寫一個(gè)文件時(shí)识虚,可以定義一個(gè)文件流對(duì)象,并將對(duì)象與文件關(guān)聯(lián)起來妒茬。每個(gè)文件流類都定義了一個(gè)名為open的成員函數(shù)担锤,它完成一些系統(tǒng)相關(guān)的操作,來定位給定的文件乍钻,并視情況打開為讀或?qū)懩J健?/p>

ifstream in(ifile); //構(gòu)造一個(gè)ifstream并打開給定文件
ofstream out; //輸出文件流并未關(guān)聯(lián)任何文件
用fstream代替iostream&

接受一個(gè)iostream類型引用參數(shù)的函數(shù)肛循,可以用一個(gè)對(duì)應(yīng)的fstream類型來調(diào)用。

成員函數(shù)open和close

如果我們定義了一個(gè)空文件流對(duì)象团赁,可以隨后調(diào)用open來將它與文件關(guān)聯(lián)起來:

ifstream in(ifile); //構(gòu)筑一個(gè)ifstream并打開給定文件
ofstream out; //輸出文件流并未與任何文件關(guān)聯(lián)
out.open(ifile + ".copy"); //打開指定文件

如果調(diào)用open失敗育拨,failbit會(huì)被置位。

自動(dòng)構(gòu)造和析構(gòu)
for(auto p = argv + 1;p != argv + argc;++p) {
    ifstream input(*p); //創(chuàng)建輸入流并打開文件
    if(input) { //如果文件打開成功欢摄,“處理”此文件
        process(input);
    }else {
        cerr << "couldn't open: " << string(*p); 
    }
} //每個(gè)循環(huán)步input都會(huì)離開作用域熬丧,因此會(huì)被銷毀。

==當(dāng)一個(gè)fstream對(duì)象被銷毀時(shí)怀挠,close會(huì)自動(dòng)被調(diào)用析蝴。==

2.2 文件模式

每個(gè)流都有一個(gè)關(guān)聯(lián)的文件模式,用來指出如何使用文件绿淋。表給出了文件模式和它們的定義:

文件模式 含義
in 以讀方式打開
out 以寫方式打開
app 每次寫操作前均定位到文件末尾
ate 打開文件后立即定位到文件末尾
trunc 截?cái)辔募?/td>
binary 以二進(jìn)制方式IO

無(wú)論用哪種方式打開文件闷畸,我們都可以指定文件模式,指定文件模式有如下限制:

  • 只可以對(duì)ofstream或fstream對(duì)象設(shè)定out模式吞滞。
  • 只可以對(duì)ifstream或fstream對(duì)象設(shè)定in模式佑菩。
  • 只有當(dāng)out也被設(shè)定時(shí)才可設(shè)定trunc模式。
  • 只要trunc沒被設(shè)定裁赠,就可以設(shè)定app模式茧痒。在app模式下桥状,即使沒有顯示指定out模式息尺,文件也總是以輸出方式被打開字币。
  • 默認(rèn)情況下,即使沒有指定trunc一忱,以out模式打開的文件也會(huì)被截?cái)嗔榱吮A粢詏ut模式打開的文件的內(nèi)容,我們必須同時(shí)指定app模式帘营,這樣只會(huì)將數(shù)據(jù)追加寫到文件末尾票渠;或者同時(shí)指定in模式,即打開文件同時(shí)進(jìn)行讀寫操作芬迄。
  • ate和binary模式可用于任何類型的文件流對(duì)象庄新,且可以與其他任何文件模式組合使用

每個(gè)文件流類型都定義了一個(gè)默認(rèn)的文件模式,當(dāng)我們未指定文件模式時(shí),就使用此默認(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模式打開羞芍。

以out模式打開文件會(huì)丟失已有數(shù)據(jù)

默認(rèn)情況下哗戈,我們打開一個(gè)ofstream時(shí),文件的內(nèi)容會(huì)被丟棄荷科。阻止一個(gè)ofstream清空給定文件內(nèi)容的方法是同時(shí)指定app模式:

//在這幾條語(yǔ)句中唯咬,file1都被截?cái)?ofstream out("file1"); //隱含以輸出模式打開文件并截?cái)辔募?ofstream out2("file1",ofstream::out); //隱含地截?cái)辔募?ofstream out3("file1",ofstream::out||ofstream::trunc);

//為了保留文件內(nèi)容,我們必須顯示指定app模式
ofstream app("file2",ofstream::app); //隱含為輸出模式
ofstream app2("file2", ofstream::out | ofstream::app);

==保留被ofstream打開文件中已有數(shù)據(jù)的唯一方法是顯示指定app或in模式畏浆。==

每次調(diào)用open時(shí)都會(huì)確定文件模式

對(duì)于一個(gè)給定流胆胰,每當(dāng)打開文件時(shí),都可以該變其文件模式:

ofstream out; //未指定文件打開模式
out.open("scratchpad"); //模式隱含設(shè)置為輸出和截?cái)?out.close(); //關(guān)閉out刻获,以便我們將其用于其他文件
out.open("precious",ofstream::app); //模式為輸出和追加
out.close();

第一個(gè)open調(diào)用沒指定輸出模式蜀涨,文件隱式地以out模式打開。通常情況下蝎毡,out模式意味著同時(shí)使用trunc模式厚柳。因此,當(dāng)前目錄名為scratchpad的文件的內(nèi)容將被清空沐兵。當(dāng)打開名為precious的文件時(shí)别垮,我們指定了append模式。文件中已有的數(shù)據(jù)都得以保留扎谎,所有寫操作都在文件末尾進(jìn)行碳想。

==每次打開文件時(shí),都要設(shè)置文件模式毁靶,可能是顯示地設(shè)置胧奔,也可能是隱式地設(shè)置。當(dāng)程序未指定模式時(shí)老充,就使用默認(rèn)值。==


#3. string流

istringstream從string讀取數(shù)據(jù)螟左,ostringstream向string寫入數(shù)據(jù)啡浊,而頭文件stringstream既可從string讀取數(shù)據(jù)也可向string寫數(shù)據(jù)。

stringstream特有的操作 含義
sstream strm; strm是一個(gè)未綁定的stringstream對(duì)象胶背。
strm.str() 返回strm所保存的string的拷貝
strm.str(s) 將string s拷貝到strm中巷嚣。返回void

3.1 使用istringstream

struct PersonInfo {
    string name;
    vector<string> phones;
};

string line, word; //分別保存來自輸入的一行和單詞
vector<PersonInfo> people; //保存來自輸入的所有記錄
//逐行從輸入讀取數(shù)據(jù),直至cin遇到文件尾
while (getline(cin,line)) {
    PersonInfo info; //創(chuàng)建一個(gè)保存此記錄的數(shù)據(jù)對(duì)象
    istringstream record(line); //將記錄綁定到剛讀入的行
    record >> info.name; //讀取名字
    while (record >> word) { //讀取電話號(hào)碼
        info.phones.push_back(word); //保存它們
    }
    people.push_back(info); //將此記錄追加到people末尾
}

3.2 使用ostringstream

但我們逐步構(gòu)造輸出钳吟,希望最后一起打印時(shí)廷粒,ostringstream是很有用的。

for(const auto &entry:people) { //對(duì)于people中的每一項(xiàng)
    ostringstream formatted,badNums; //每個(gè)循環(huán)步創(chuàng)建的對(duì)象
    for(const auto &nums:entry.phones) {
        if(!valid(nums)) {
            badNums << " " << nums; //將數(shù)的字符串形式存入badNums
        }else {
            formatted << " " << format(nums);
        }
    }
    if(badNums.str().empty()) { //沒有錯(cuò)誤的數(shù)
        os << entry.name << " "
        <<formatted.str() << endl;
    }else {
        cerr << "input error: " << entry.name 
            <<" invalid numbers " << badNums.str() << endl;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市坝茎,隨后出現(xiàn)的幾起案子涤姊,更是在濱河造成了極大的恐慌,老刑警劉巖嗤放,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件思喊,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡次酌,警方通過查閱死者的電腦和手機(jī)恨课,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岳服,“玉大人剂公,你說我怎么就攤上這事〉跛危” “怎么了纲辽?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)贫母。 經(jīng)常有香客問我文兑,道長(zhǎng),這世上最難降的妖魔是什么腺劣? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任绿贞,我火速辦了婚禮,結(jié)果婚禮上橘原,老公的妹妹穿的比我還像新娘籍铁。我一直安慰自己,他們只是感情好趾断,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布拒名。 她就那樣靜靜地躺著,像睡著了一般芋酌。 火紅的嫁衣襯著肌膚如雪增显。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天脐帝,我揣著相機(jī)與錄音同云,去河邊找鬼。 笑死堵腹,一個(gè)胖子當(dāng)著我的面吹牛炸站,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疚顷,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼旱易,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼禁偎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阀坏,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤如暖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后全释,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體装处,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年浸船,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妄迁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡李命,死狀恐怖登淘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情封字,我是刑警寧澤黔州,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站阔籽,受9級(jí)特大地震影響流妻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜笆制,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一绅这、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧在辆,春花似錦证薇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至鸦概,卻和暖如春箩张,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背窗市。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工先慷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谨设。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓熟掂,卻偏偏與公主長(zhǎng)得像缎浇,于是被迫代替她去往敵國(guó)和親扎拣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 8.1 IO類 IO類繼承機(jī)制:ifstream和istringstream繼承自istream,ofstream...
    咸魚翻身ing閱讀 219評(píng)論 0 0
  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說明:當(dāng)在唯一索引所對(duì)應(yīng)的列上鍵入重復(fù)值時(shí)二蓝,會(huì)觸發(fā)此異常誉券。 O...
    我想起個(gè)好名字閱讀 5,176評(píng)論 0 9
  • 一、基礎(chǔ)知識(shí):1刊愚、JVM踊跟、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機(jī)...
    殺小賊閱讀 2,365評(píng)論 0 4
  • 概述 java.io 包幾乎包含了所有操作輸入、輸出需要的類鸥诽。所有這些流類代表了輸入源和輸出目標(biāo)商玫。java.io ...
    Steven1997閱讀 9,178評(píng)論 1 25
  • 1 C++緩沖區(qū) 在學(xué)習(xí)標(biāo)準(zhǔn)IO庫(kù)之前,我們先了解C++中緩沖區(qū)的使用牡借。關(guān)于操作系統(tǒng)中緩沖區(qū)的學(xué)習(xí)與理解拳昌,請(qǐng)查看操...
    saviochen閱讀 876評(píng)論 0 4