C++ Primer 5th學習筆記7 IO庫

IO庫

1 IO類

常用的IO庫類型和頭文件如下表:

頭文件 類型
iostream istreamwistream從流讀取數據
ostreamwostream 向流寫入數據
iostreamwiostream 讀寫流
fstream ifstreamwifstream 從文件讀取數據
ostreamwofstream 向文件寫入數據
fstreamwfstream 讀寫文件
sstream istringstreamwistringstream 從string讀取數據
ostringstreamwostringstream 向string寫入數據
stringstreamwstringstream 讀寫string

w開頭的表示寬字符類型

1.1 條件狀態

IO庫條件狀態
名稱 描述
strm::iostate strm是一種IO類型,在上表中已列出
strm::badbit 用來指出流已經崩潰
strm::failbit 用來指出一個IO操作失敗了
strm::eofbit 用來指出流到達了文件結束
strm::goodbit 用來指出流未處於錯誤狀態
s.eof() 若流s的eofbit置位,則返回true
s.fail() 若流s的failbitbadbit置位,則返回true
s.bad() 若流s的badbit置位,則返回true
s.good() 若流s處於有效狀態,則返回true
s.clear() 將流s中所有條件狀態復位,將流的狀態設置爲有效。返回void
s.clear(flags) 根據給定的flag標誌位,將流s中對應條件狀態位復位。flag類型爲strm::iostate
s.setstate(flags) 根據給定的flag標誌位,將流s中對應條件狀態位置位。flag類型爲strm::iostate
s.rdstate() 返回流s的當前條件狀態,返回類型爲strm::iostate

1.2 管理輸出緩衝

  每一個輸出流都管理一個緩衝區,用來保存程序讀寫的數據。其中導致緩衝區刷新的原因有如下幾種:

  • 程序正常結束
  • 緩衝區滿時,需要刷新緩衝區,後面新來的數據才能繼續寫入緩衝區
  • 使用操作符如endl來顯示刷新緩衝
  • 在每個輸出操作之後,可以用操作符unitbuf設置流的內部狀態,來清空緩衝區
  • 一個輸出流可能被關聯到另一個流,當讀寫被關聯的流時,關聯到的流的緩衝區會被刷新

刷新輸出緩衝區操作符:flush和ends,其中flush刷新緩衝區,但不輸出任何額外的字符;ends向緩衝區插入一個空字符,然後刷新緩衝區。

2 文件輸入輸出

  頭文件fstream定義了三個類型來支持文件IO:ifstream從一個給定文件讀取數據,ofstream向一個給定文件寫入數據,fstream可以讀寫給定文件

`fstream`特有的操作
名稱 描述
fstream fstrm; 創建一個未綁定的文件流
fstream fstrm(s); 創建一個fstream,並打開名爲s的文件,s可以是string類型,或指向C風格字符串的指針
fstream fstrm(s, mode); 創建一個fstream,並打開名爲s的文件,按指定mode打開文件
fstrm.open(); 打開名爲s的文件,並將文件與fstrm綁定
fstrm.close(); 關閉與fstrm綁定的文件。返回void
fstrm.is_open(); 返回一個bool值,表示與fstrm關聯的文件是否打開成功並且尚未關閉

示例:

ifstream in(ifile);       //創建一個ifstream並打開給定文件
ofstream out;        //輸出文件流
out.open(ifile + ".txt");        //打開指定文件

2.1 文件模式

文件模式
操作 描述
in 以讀方式打開文件
out 以寫方式打開文件
app 每次寫操作前均定位到文件末尾
ate 打開文件後立即定位到文件末尾
trunc 截斷文件
binary 以二進制方式進行IO

指定文件模式有如下限制:

  • 只可以對ofstreamfstream對象設定out模式
  • 只可以對ifstreamfstream對象設定in模式
  • 只有當out也被設定時,纔可設定trunc模式
  • ate和binary模式可用於任何類型的文件流對象,且可以與其他任何文件模式組合使用
  • 只要trunc沒有被設定。就可以設定app模式。在app模式下即使沒有顯式指定out模式,文件也總是以輸出方式被打開。
  • 即使沒有指定trunc,以out模式打開的文件也會被截斷,因此爲保留此時的內容,必須同時指定app模式,這樣數據將追加寫到文件末尾

Tips:當打開一個ofstream時文件的內容會被丟棄,因此此時必須顯式指定app或in模式
示例如下:

//文件內容會被截斷
ofstream app("file2");
ofstream app("file2", ofstream::out);
//文件內容保留
ofstream app("file2", ofstream::app);
ofstream app("file2", ofstream::out | ofstream::app);

3 string流

string特有的操作
名稱 描述
sstream strm; strm是一個未綁定的stringstream對象。sstream是頭文件sstream中定義的一個類型
sstream strm(s); strm是一個sstream對象,保存string s的一個拷貝
strm.str() 返回strm所保存的string的拷貝
strm.str(s) string s拷貝到strm中,返回void

3.1 使用istringstream

示例如下:
現有一個這樣的文件,其輸入格式如下:

morgan 2015552368 8625550123
drew 9735550130
lee 6095550132 2015550175 8005550000

首先定義一個簡單的類來描述輸入數據:

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

讀取信息的實例函數如下:

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

這裏的istringstreamgetline讀取的文本進行綁定,然後在istringstream上使用輸入運算符來讀取當前記錄中的每個元素,即元素之間以空格爲區分。

3.2 使用ostringstream

對於上例,現將每個人的電話打印出來,但是不希望輸出無效電話號碼的人,因此需要進行驗證。此時可以先將要輸出的內容“寫入”到一個內存ostringstream中,其代碼如下:

for(const auto &entry : people)          //對people中的每一項
{
    ostringstream formatted,badNums;     //每個循環步創建的對象
    for(const auto &num : entry.phones)  //對每個數
    {
        if(!valid(nums))
        {
            badNums << " " << nums;      //將數的字符串形式存入badNums
        }
        else
        formatted << " " << format(num); //將格式化的字符串“寫入”formatted
    }
    if(bad.Nums.str().empty())           //沒有錯誤的數
    //打印名字和格式化的數
    os << entry.name << " " << formatted.str() << endl;
    else//打印名字和錯誤的數
    ceer << "input error: " << entry.name 
         << " invalid number(s)" << badNums.str() << endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章