日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ 流的操作 | 初识IO类、文件流、string流的使用

發布時間:2023/12/13 c/c++ 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ 流的操作 | 初识IO类、文件流、string流的使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • IO頭文件
    • iostream
    • fstream
    • sstream
  • 流的使用
    • 不能拷貝或對 IO對象 賦值
    • 條件狀態與 iostate 類型
  • 輸出緩沖區
  • 文件流
    • fstream類型
    • 文件模式
  • string流
    • istringstream
    • ostringstream


前言

我們在使用 C++ 的過程中,總避免不了 IO操作,比如經常用到的一些 IO庫設施:

  • istream:(輸入流)類型,提供輸入操作。
  • ostream:(輸出流)類型,提供輸出操作。
  • cin:一個 istream 對象,從標準輸入讀取數據。
  • cout:一個 ostream 對象,向標準輸出寫入數據。
  • cerr:一個 ostream 對象,通常用于輸出程序錯誤消息,寫入到標準錯誤。
  • >>運算符:用來從一個 istream 對象讀取輸入數據。
  • <<運算符:用來向一個 ostream 對象寫入輸出數據。
  • getline函數:從一個給定的 istream 讀取一行數據,存入一個給定的 string 對象中。

但實際上可能僅僅是懵懵懂懂在使用,如果不深入了解的話,實際上這樣的使用是淺薄的。


IO頭文件

iostream

定義了用于讀寫的基本類型。

  • istream,wistream 從流讀取數據
  • ostream,wostream 向流寫入數據
  • iostream,wiostream 讀寫流

fstream

定義了讀寫命名文件的類型。

  • ifstream,wifstream 從文件讀取數據
  • ofstream,wofstream 向文件寫入數據
  • fstream,wfstream 讀寫文件

sstream

定義了讀寫內存string對象的類型。

  • istringstream,wistringstream 從 string 讀取數據
  • ostringstream,wostringstream 向 string 寫入數據
  • stringstream,wstringstream 讀寫 string

流的使用

標準庫通過繼承使我們忽略不同類型流之間的差異。舉例來說,類型 ifstream 和 istringstream 都繼承自 istream。因此,我們如何使用 cin ,就可以同樣地使用這些類型的對象。

不能拷貝或對 IO對象 賦值

ofstream out1, out2; out1 = out2; // error:不能對流對象賦值 ofstream printf(ofstream); // error: 不能初始化ofstream參數 out2 = printf(out2); // error: 不能拷貝流對象
  • 由于不能拷貝IO對象,因此我們也不能將形參返回類型設置為流類型。
  • 進行IO操作的函數通常以引用方式傳遞和返回流。讀寫一個IO對象會改變其狀態,因此傳遞和返回的引用不能是const的。

條件狀態與 iostate 類型

IO操作使用不當的話會發生錯誤,而如果是發生在系統深處的錯誤,那么就超出了應用程序可以修正的范圍。但也有一些錯誤是可以恢復的,IO類也提供了一些函數和標志來訪問、操縱流的條件狀態


下面對表中的四個條件位作進一步介紹。

iostate 類型

IO庫定義了一個與機器無關的 iostate 類型,它提供了表達流狀態功能。

IO庫定義了 4個 iostate類型 的 constexpr 值(常量表達式),表示特定的位模式

  • badbit: 表示系統級錯誤,如不可恢復的讀寫錯誤。通常情況下,一旦 badbit 被置位,流就無法再使用了。
  • failbit: 在發生可恢復錯誤后被置位,如期望讀取數值卻讀出一個字符等錯誤。這種問題通常是可以修正的,流還可以繼續使用。
  • eofbit: 如果到達文件結束位置,連同 failbit 一起被置位。
  • goodbit: 值為 0 時,表示流未發生錯誤。

對他們進行一個簡單的使用:

auto old_state = cin.rdstate(); // 返回流cin的當前狀態,返回值類型為 strm::iostate cin.clear(); // 將cin所有條件位復位,換言之,使cin有效 // clear重載版本允許有參數,接受一個iostate值,表示流的新狀態 cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit); // 先用rdstate讀出當前條件狀態,再將failbit和badbit復位生成新狀態。 process_input(cin); // 使用cin cin.setstate(old_state); // 將cin置為原有狀態

輸出緩沖區

以前對于輸出緩沖區是沒什么概念的……直到在做美團往年筆試題的時候,有道編程題如果用 endl 作為換行會報超時,原因是 endl 頻繁刷新輸出緩沖區,因此需要用 '\n' 。

操作系統的 IO操作 是很耗時的,緩沖機制使操作系統將程序的多個輸出操作組合成單一的系統級寫操作(寫到顯示設備上),對性能的提升是巨大的。

導致緩沖刷新(數據真正寫到輸出設備或文件)的原因有很多:

  • 程序正常結束,作為 main函數 的 return操作 的一部分,緩沖刷新被執行。
  • 緩沖區滿時,需要刷新緩沖,而后新的數據才能繼續寫入緩沖區。
  • 我們可以使用操縱符(如 endl) 來顯式刷新緩沖區。
  • 在每個輸出操作之后,我們可以用 操縱符unitbuf 設置流的內部狀態,來清空緩沖區。默認情況下,對 cerr 是設置 unitbuf 的,因此寫到 cerr 的內容都是立即刷新的。
  • 一個輸出流可能被關聯到另一個流。在這種情況下,當讀寫被關聯的流時,關聯到的流的緩沖區會被刷新。例如,默認情況下,cin 和cerr 都關聯到 cout。因此,讀 cin 或寫 cerr 都會導致 cout 的緩沖區被刷新。
  • 關于第三點,共有三種操作符可用來刷新緩沖:

    • endl: 換行并刷新緩沖區
    • flush: 僅刷新緩沖區,但不輸出任何額外字符
    • ends: 向緩沖區插入一個空字符然后刷新緩沖區

    關于第四點:

    • unitbuf操縱符: 每次寫操作之后都進行一次 flush 操作
    • nounitbuf操縱符: 重置流,使其恢復默認的緩沖區刷新機制

    值得一提的是,如果程序崩潰,輸出緩沖區不會被刷新。

    關于第五點,C++提供了 tie函數 來查看當前對象關聯的輸入輸出流,tie 有兩個重載版本:

    • 無參數版本: 返回指向輸出流的指針。當前對象若關聯了一個輸出流,則返回指向該流的指針;若未關聯流,則返回空指針
    • 參數為一個指向 ostream 的指針: 將當前對象關聯到此 ostream 。

    每個流同時最多關聯到一個流,但多個流可以同時關聯到同一個 ostream 。

    示例:

    cin.tie(&cout); // 標準庫默認將 cin 和 cout 關聯在一起 cin.tie() = cin.tie(nullptr); // 通過傳遞空指針,讓 cin 不再與其他流關聯

    文件流

    fstream類型

    除了繼承自 iostream類型 的行為外,fstream類型 還增加了一些新的成員來管理與流關聯的文件。

    open函數

    fstrm(s) 之所以能在調用時打開文件s,是因為自動調用了 open函數 ,等價于:

    ifstream in; // 輸入文件流未與任何文件關聯 in.open(ifile); // 打開指定文件,并與in綁定

    對一個已經打開的文件流調用 open 會失敗,此時 failbit 會被置位,隨后使用文件流的操作都會失敗。因此,調用 open 后檢測是否成功是個好習慣:

    if(in) // 成功 else // 不成功

    如果想要將文件流關聯到另一個文件,必須先關閉已關聯的文件:

    in.cloes(); in.open(ifile);

    open 成功調用會將 good() 設為 true。

    close函數

    當一個 fstream對象 被銷毀時,close 會自動被調用。


    文件模式

    每個文件流類型都定義了一個默認的文件模式,當我們未指定文件模式時,就使用此默認模式。

    • 與 ifstream關聯 的文件默認以 in模式 打開;
    • 與 ofstream關聯 的文件默認以 out模式 打開;
    • 與 fstream關聯 的文件默認以 in和out模式 打開。

    雖然不論是調用 open 打開文件,還是 fstrm(s) 這樣隱式打開文件,都可以指定文件模式,但指定文件模式有如下限制:

  • 只可以對 ofstream、 fstream 對象設定 out 模式。
  • 只可以對 ifstream、 fstream 對象設定 in 模式。
  • 只有 out 也被設定時才可設定 trunc 模式。
  • 只要 trunc 沒被設定,就可以設定 app 模式。在 app 模式下,即使沒有顯式指定 out 模式,文件也總是以輸出方式被打開。
  • 默認情況下,以 out 模式打開的文件同時使用 trunc 模式,即會被截斷(內容被丟棄)。
    • 為了保留以 out 模式打開的文件的內容,我們必須同時指定 app 模式,這樣只會將數據追加寫到文件末尾;
    • 或者同時指定 in 模式,即打開文件同時進行讀寫操作。
  • ate 和 binary 模式可用于任何類型的文件流對象,且可以與其他任何文件模式組合使用。
  • 關于第五點,舉例詳細講一下:

    /*截斷*/ ofstream out1("file1"); // 隱含以out模式打開文件并截斷文件 ofstream out2("file1", ofstream::out); // 隱含地截斷文件 ofstream out3("file1", ofstream::out | ofstream::trunc); // 顯式實現out模式打開文件并截斷/*app模式保留文件內容*/ ofstream app1("file2", ofstream:app); // 隱含out模式 ofstream app2("file2", ofstream:out | ofstream:app);

    string流

    同樣的,除了繼承自 iostream 的操作,sstream 也增加了獨有的操作。

    istringstream

    我們經常會碰到處理整行字符串的問題,比如:比較版本號

    用雙指針截取字符串當然是一種方法,但是使用 istringstream 這個標準庫提供的利器會更加方便。當然,兩種方法的時間、空間復雜度是一樣的。

    下面通過分析 istringstream 的使用來進一步理解如何用:

    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數據到a中,遇到空白符or非int數據停下in2 >> b;if(a > b) return 1;if(a < b) return -1;a = b = 0;in1 >> c; // 從in1中讀取char類型數據到c中,遇到空白符or非char數據停下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數組中people.push_back(pp); // 將這個人的信息保存在people數組中 }

    ostringstream

    當我們希望將多個輸出最后一起打印時,ostringstream 是很有用的。舉個簡單的例子:

    ostringstream out; // 創建一個未綁定的輸出流 vector<string> vs = {"cmy", "lx", "lhy"}; for (string s : vs) {out << s << " "; } cout << out.str() << endl; // str():返回out保存的string的拷貝,也就是將out轉換為string類型。

    我們使用標準的輸出運算符<<向 out 寫入數據,有趣的是,這些寫入操作實際上轉換為 string 操作,向 out 中的 string 對象添加字符。

    總結

    以上是生活随笔為你收集整理的C++ 流的操作 | 初识IO类、文件流、string流的使用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。