8.2文件輸入輸出
- 頭文件fstream定義了三個類型來支持文件IO:ifstream從一個給定文件讀取數據,ofstream向一個給定文件寫入數據,以及fstream可以讀寫給定文件。在17.5.3節中(第676頁)我們將介紹如何對同一個文件流既讀又寫。
- 這些類型提供的操作與我們之前已經使用過的對象cin和cout的操作一樣。特別是,我們可以用IO運算符(<<和>>)來讀寫文件,可以用getline(參見3.2.2節,第79頁)從一個ifstream讀取數據,包括8.1節中(第278頁)介紹的內容也都適用于這些類型。
- 除了繼承自iostream類型的行為之外,fstream中定義的類型還增加了一些新的成員來管理與流關聯的文件。在表8.3中列出了這些操作,我們可以對fstream,ifstream和ofstream對象調用這些操作,但不能對其他IO類型調用這些操作。

8.2.1使用文件流對象
- 當我們想要讀寫一個文件時,可以定義一個文件流對象,并將對象與文件關聯起來。每個文件流類都定義了一個名為open的成員函數,它完成一些系統相關的操作,來定位給定的文件,并視情況打開為讀或寫模式。
- 創建文件流對象時,我們可以提供文件名(可選的)。如果提供了一個文件名,則open會自動被調用:
- ifstreamin(ifile);//構造一個ifstream并打開給定文件
- ofstream out;//輸出文件流未關聯到任何文件
- 這段代碼定義了一個輸入流in,它被初始化為從文件讀取數據,文件名由string類型的參數ifile指定。第二條語句定義了一個輸出流out,未與任何文件關聯。在新C++重標準中,文件名既可以是庫類型string對象,也可以是C風格字符數組(參見3.5.4節,1第109頁)。舊版本的標準庫只允許C風格字符數組。
用fstream代替iostream&
- 在8.1節(第279頁)已經提到過,在要求使用基類型對象的地方,我們可以用繼承類型的對象來替代。這意味著,接受一個iostream類型引用(或指針)參數的函數,可以用一個對應的fstream(或sstream)類型來調用。也就是說,如果有一個函數接受一個ostream&參數,我們在調用這個函數時,可以傳遞給它一個ofstream對象,對istream&和ifstream也是類似的。
成 員 函 數 open和 close
- 如果我們定義了一個空文件流對象,可以隨后調用open來將它與文件關聯起來:
- ifstream in(ifile);//構筑一個ifstream并打開給定文件
- ofstream out;//輸出文件流未與任何文件相關聯
- out.open(ifile+*'.copy");//打開指定文件
- 如果調用open失敗,failbit會被置位(參見8.1.2節,第280頁)。因為調用open可能失敗,進行Open是否成功的檢測通常是一個好習慣:
- if(out)//檢查open是否成功
- //open成功,我們可以使用文件了
- 這個條件判斷與我們之前將cin用作條件相似。如果open失敗,條件會為假,我們就不會去使用out了。
- 一旦一個文件流已經打開,它就保持與對應文件的關聯。實際上,對一個已經打開的文件流調用open會失敗,并會導致failbit被置位。隨后的試圖使用文件流的操作都會失敗。為了將文件流關聯到另外一個文件,必須首先關閉已經關聯的文件。一旦文件成功關閉,我們可以打開新的文件:
- in.close();//關閉文件
- in.open(ifile+“2”);//打開另一個文件如果open成功,則open會設置流的狀態,使得good()為true。
自動構造和析構
- 考慮這樣一個程序,它的main函數接受一個要處理的文件列表(參見6.2.5節,第】96頁)。這種程序可能會有如下的循環:
- //對每個傳遞給程序的文件執行循環操作
//對每個傳遞給程序的文件執行循環操作for (auto p = argv + 1; p < argv + argc; ++p) {std::ifstream input(*p); //創建輸出流并且打開文件if (input){ //如果文件打開成功,“處理”這個文件//process(input); } else{std::cerr << "couldn‘t open: " + std::string(*p);}}//每個循環步input都會離開作用域,因此會被銷毀
- 每個循環步構造一個新的名為input的ifstream對象,并打開它來讀取給定的文件。像之前一樣,我們檢查open是否成功。如果成功,將文件傳遞給一個函數,該函數負責讀取并處理輸入數據。如果open失敗,打印一條錯誤信息并繼續處理下一個文件。因為input是while循環的局部變量,它在每個循環步中都要創建和銷毀一次(參見5.4.1節,第165頁)。當一個fstream對象離開其作用域時,與之關聯的文件會自動關閉。在下一步循環中,input會再次被創建。
- 當一個fstream對象被銷毀時,close會自動被調用。
8 .2 .2 文件模式
- 每個流都有一個關聯的文件模式(file mode),用來指出如何使用文件。表 8.4列出了 文件模式和它們的含義。

- 無論用哪種方式打開文件,我們都可以指定文件模式,調用。pen打開文件時可以,用一個文件名初始化流來隱式打開文件時也可以。指定文件模式有如下限制:
- 只可以對ofstream或fstream對象設定out模式。
- 只可以對ifstream或fstream對象設定in模式。
- 只有當out也被設定時才可設定trunc模式。
- 只要trunc沒被設定,就可以設定app模式。在app模式下,即使沒有顯式指定out模式,文件也總是以輸出方式被打開。
- 默認情況下,即使我們沒有指定trunc,以out模式打開的文件也會被截斷。為了保留以out模式打開的文件的內容,我們必須同時指定app模式,這樣只會將數據追加寫到文件末尾;或者同時指定in模式,即打開文件同時進行讀寫操作(參見17.5.3節,第676頁,將介紹對同一個文件既進行輸入又進行輸出的方法)。
- ate和binary模式可用于任何類型的文件流對象,且可以與其他任何文件模式組合使用。
- 每個文件流類型都定義了一個默認的文件模式,當我們未指定文件模式時,就使用此默認模式。與ifstream關聯的文件默認以in模式打開;與ofstream關聯的文件默認以out模式打開;與fstream關聯的文件默認以in和out模式打開。
以out模式打開文件會丟棄已有數據
- 默認情況下,當我們打開一個ofstmam時,文件的內容會被丟棄。阻止一個ofstream清空給定文件內容的方法是同時指定app模式:
- //在這幾條語句中,filel都被截斷
- ofstream out("file1");//隱含以輸出模式打開文件并截斷文件
- ofstream out2("file1",ofstream::out);//隱含地截斷文件
- ofstreamout3("file1",ofstream::out|ofstream::trunc);
- //為了保留文件內容,我們必須顯式指定app模式
- ofstream app("file2”,ofstream::app);//隱含為輸出模式
- ofstreamapp2(nfile2n,ofstream::out|ofstream::app);
- 保留被ofstream打開的文件中已有數據的唯一方法是顯式指定app或 in 模式
每次調用open時都會確定文件模式
- 對于一個給定流,每當打開文件時,都可以改變其文件模式。
- ofstreamout;//未指定文件打開模式
- out.open(^scratchpad");//模式隱合設置為輸出和截斷
- out.close();//關閉out,以便我們將其用于其他文件
- out.open("precious",ofstream::app);//模式為輸出和追加
- out.close();
- 第一個open調用未顯式指定輸出模式,文件隱式地以out模式打開。通常情況下,out模式意味著同時使用trunc模式。因此,當前目錄下名為scratchpad的文件的內容將被清空。當打開名為precious的文件時,我們指定了append模式(app)。文件中已有的數據都得以保留,所有寫操作都在文件末尾進行。
- 在每次打開文件時,都要設置文件模式,可能是顯式地設置,也可能是隱式地也設置當程序未指定模式時,就使用默認值。