C++基礎教程面向對象(學習筆記(106))

基本文件I / O

C ++中的文件I / O與普通I / O非常相似(有一些小的複雜性)。C ++中有3個基本文件I / O類:ifstream(派生自istream),ofstream(派生自ostream)和fstream(派生自iostream)。這些類分別進行文件輸入,輸出和輸入/輸出。要使用文件I / O類,您需要包含fstream標頭。

與已經可以使用的cout,cin,cerr和clog流不同,文件流必須由程序員明確設置。但是,這非常簡單:打開一個文件進行讀取和/或寫入,只需實例化相應文件I / O類的對象,並將文件名作爲參數。然後使用插入(<<)或提取(>>)運算符來寫入或讀取文件中的數據。完成後,有幾種方法可以關閉文件:顯式調用close()函數,或者讓文件I / O變量超出範圍(文件I / O類析構函數將爲您關閉文件) 。

文件輸出

要在以下示例中執行文件輸出,我們將使用ofstream類。這非常簡單:

#include <fstream>
#include <iostream>
#include <cstdlib> //exit()
 
int main()
{
    using namespace std;
 
    // ofstream用於寫入文件
    // 我們將創建一個名爲Sample.dat的文件
    ofstream outf("Sample.dat");
 
    //如果我們無法打開輸出文件流進行寫入
    if (!outf)
    {
        // 打印錯誤並且退出
        cerr << "Uh oh, Sample.dat could not be opened for writing!" << endl;
        exit(1);
    }
 
    // 我們將在這個文件中寫入兩行
    outf << "This is line 1" << endl;
    outf << "This is line 2" << endl;
 
    return 0;
	
    // 當超出範圍
    //  這個ofstream析構函數將關閉這個文件
}

如果查看項目目錄,應該會看到一個名爲Sample.dat的文件。如果用文本編輯器打開它,你會發現它確實包含我們寫入文件的兩行。

請注意,也可以使用put()函數將單個字符寫入文件。

文件輸入

現在,我們將獲取我們在上一個示例中編寫的文件,並從磁盤中讀回來。請注意,如果我們已到達文件末尾(EOF),ifstream將返回0。我們將使用這個事實來確定要閱讀多少。

#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib> // exit()
 
int main()
{
    using namespace std;
 
    // ifstream用於讀取文件
    // 我們將從一個名爲Sample.dat的文件中讀取
    ifstream inf("Sample.dat");
 
    //如果我們無法打開輸出文件流進行讀取
    if (!inf)
    {
        // 打印錯誤並且退出
        cerr << "Uh oh, Sample.dat could not be opened for reading!" << endl;
        exit(1);
    }
 
    // 雖然還有東西可以read
    while (inf)
    {
        // 將文件中的內容讀入字符串並打印出來
        std::string strInput;
        inf >> strInput;
        cout << strInput << endl;
    }
    
    return 0;
	
    // 當超出範圍
    //  這個ofstream析構函數將關閉這個文件
}

這會產生結果:

This
is
line
1
This
is
line
2

嗯,那不是我們想要的。請記住,提取運算符處理“格式化輸出”,並在空白處打破。爲了讀取整行,我們必須使用getline()函數。

#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib> // exit()
 
int main()
{
    using namespace std;
 
    // ifstream用於讀取文件
    // 我們將從一個名爲Sample.dat的文件中讀取
    ifstream inf("Sample.dat");
 
    // 如果我們無法打開輸入文件流進行讀取
    if (!inf)
    {
        // 打印錯誤並且退出
        cerr << "Uh oh, Sample.dat could not be opened for reading!" << endl;
        exit(1);
    }
 
    // 雖然還有一些東西需要閱讀
    while (inf)
    {
        // 將文件中的內容讀入字符串並打印出來
        std::string strInput;
        getline(inf, strInput);
        cout << strInput << endl;
    }
    
    return 0;
	
    // 當超出範圍
    //  這個ofstream析構函數將關閉這個文件
}

這會產生結果:
This is line 1
This is line 2
緩衝輸出

可以緩衝C ++中的輸出。這意味着輸出到文件流的任何內容都可能無法立即寫入磁盤。相反,可以對幾個輸出操作進行批處理和一起處理。這主要是出於性能原因。將緩衝區寫入磁盤時,這稱爲刷新緩衝區。導致緩衝區刷新的一種方法是關閉文件,緩衝區的內容將刷新到磁盤,然後文件將被關閉。

緩衝通常不是問題,但在某些情況下,它可能導致不警惕的併發症。在這種情況下,主要的罪魁禍首是緩衝區中有數據,然後程序立即終止(通過崩潰或通過調用exit())。在這些情況下,不執行文件流類的析構函數,這意味着文件永遠不會關閉,這意味着永遠不會刷新緩衝區。在這種情況下,緩衝區中的數據不會寫入磁盤,並且會永久丟失。這就是爲什麼在調用exit()之前顯式關閉任何打開的文件總是一個好主意。

可以使用ostream :: flush()函數手動刷新緩衝區或將std :: flush發送到輸出流。這些方法中的任何一個都可以用於確保緩衝區的內容立即寫入磁盤,以防程序崩潰。

一個有趣的注意事項是std :: endl; 還會刷新輸出流。因此,過度使用std :: endl(導致不必要的緩衝區刷新)會在執行緩衝I / O時產生性能影響,其中刷新是昂貴的(例如寫入文件)。出於這個原因,具有性能意識的程序員通常會使用’\ n’而不是std :: endl在輸出流中插入換行符,以避免不必要的緩衝區刷新。

文件模式

如果我們嘗試寫入已存在的文件會發生什麼?再次運行輸出示例顯示每次運行程序時都會完全覆蓋原始文件。相反,如果我們想在文件的末尾添加更多數據呢?事實證明,文件流構造函數採用可選的第二個參數,允許您指定有關如何打開文件的信息。此參數稱爲模式,它接受的有效標誌位於Ios類中。

Ios文件模式 含義
app 以附加模式打開文件
ate 在讀/寫之前尋找文件的末尾
binary 以二進制模式打開文件(而不是文本模式)
in 以讀取模式打開文件(ifstream的默認值)
out 以寫入模式打開文件(ofstream的默認值)
trunc 如果文件已存在,則刪除該文件

可以通過將它們按位OR運算來指定多個標誌(使用|運算符)。Ifstream默認爲ios :: in file模式。Ofstream默認爲ios :: out文件模式。並且fstream默認爲ios :: in | ios :: out文件模式,意味着您可以默認讀取和寫入。

讓我們編寫一個程序,將另外兩行添加到我們之前創建的Sample.dat文件中:

#include <cstdlib> // for exit()
#include <iostream>
#include <fstream>
 
int main()
{
    using namespace std;
 
    // 我們將通過ios:app標誌告訴ofstream追加
    // 而不是重寫文件。我們不需要傳入ios :: out
    // 因爲ofstream默認爲ios :: out
    ofstream outf("Sample.dat", ios::app);
 
    // 如果我們無法打開輸出文件流進行寫入
    if (!outf)
    {
        // 打印錯誤並退出
        cerr << "Uh oh, Sample.dat could not be opened for writing!" << endl;
        exit(1);
    }
 
    outf << "This is line 3" << endl;
    outf << "This is line 4" << endl;
    
	return 0;
	
    // 當超出範圍
    //  這個ofstream析構函數將關閉這個文件
}

現在,如果我們看看Sample.dat(使用上面打印其內容的示例程序之一,或者在文本編輯器中加載它),我們將看到以下內容:

This is line 1
This is line 2
This is line 3
This is line 4
使用open()顯式打開文件

就像可以使用close()顯式關閉文件流一樣,也可以使用open()顯式打開文件流。open()的工作方式與文件流構造函數一樣,它採用文件名和可選的文件模式。

例如:

ofstream outf("Sample.dat");
outf << "This is line 1" << endl;
outf << "This is line 2" << endl;
outf.close(); // 顯式關閉文件
 
// 哎呀,我們忘記了什麼
outf.open("Sample.dat", ios::app);
outf << "This is line 3" << endl;
outf.close();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章