天天看點

C++ iostream 輸入輸出流

C++ 輸入輸出流:簡單地介紹了【輸入輸出流】、【檔案輸入輸出流】和【字元串輸入輸出流】。

目錄

  • STL 輸入輸出流:整體架構
  • A) 輸入、輸出流
    • 1. 簡介
    • 2. 格式化輸出
    • 3. 流操縱算子
    • 4.

      cout

      對象的唯一性
  • B) 檔案輸入、輸出流
    • 1. 基本使用方法
    • 2. 讀入常用操作
  • C) 字元串輸入、輸出流
    • 1. 簡介
    • 2. 對象内的 buffer
    • 3. 實作類型轉換

STL 輸入輸出流:整體架構

頭檔案 定義在頭檔案裡的類 / 對象 補充說明

<istream>

istream

類、

iostream

istream

類是所有輸入流的基類

<ostream>

ostream

ostream

類是所有輸出流的基類

<iostream>

cin

對象、

cout

對象

cin

istream

類的對象;

cout

ostream

類的對象

<fstream>

ifsream

類、

ofstream

類、

fstream

<sstream>

istringstream

類、

ostringstream

類、

stringstream

回到頂部

A) 輸入、輸出流

***

istream

ostream

類似,以下以

ostream

展開說明。

1. 簡介

  • ostream

    = output stream
    • 是所有輸出流的基類
    • 類内重載了不同基礎資料類型的輸出流運算符,如:

      int

      char

      bool

      ...
    • 優勢:統一了輸出接口,避免輸出混亂
  • STL 中定義了一個

    ostream

    類的對象:

    cout

    ,将資料送到标準輸出流

    以下是自定義實作

    ostream

    的方法:
    class ostream {
    public:
        ostream& operator<< (int num) {
            printf("%d", num);
            return *this;
        }
        ostream& operator<< (const char* str) {
            printf("%s", str);
            return *this;
        }
        ...... // 重載需要輸出的類型
        
    } cout; // 定義 ostream 類的對象
    
    int main() {
        cout << 21 << "happy" ; // 根據輸出資料類型,調用不同的輸出函數
        return 0;
    }
               
    以下是在自定義類中重載流運算符的方法:
    class MyClass {
    public:
        friend ostream& operator<< (ostream&, MyClass&);
        ......
    }
    
    ostream& operator<< (ostream& output, MyClass& x) {
        output << ... ;
        return outpur;
    }
               
    注意:第二個參數可以是不同形式,不一定是引用,如:

    T

    T&

    const T

    const T&

回到頂部

2. 格式化輸出

  • 常用的格式化輸出方式有:
    #include <iomanip>
    
    cout << fixed << 3 << " " << 3.14 << " " << 3.14159265;  
    /* 将小數的小數點固定為 6 位
       輸出結果:3  3.140000  3.141593  */
    
    
    cout << setprecision(3) << 3.1415926 << 0.1054;   
    /* 設定有效數字
       輸出結果:3.14  0.105  */
    
    
    cout << fixed << setprecision(2) << 3.1415;
    /* fixed 和 setprecision 合用,可以設定小數點數位
       輸出結果:3.14  */
    
    
    cout << setw(5) << 921;
    /* 設定輸出的寬度,一次隻對一個輸出有效
       預設向右對齊  */
    
    
    for(int i = 8; i <= 12; ++i) {
        cout << setw(5) << setfill('*') << i;
    }
    /* 設定輸出的寬度 + 空白處填滿指定字元
       輸出結果:****8****9***10***11***12  */
    
    
    cout << scientific << 2018.0 << " " << 0.0001;
    /* 以科學計數形式輸出
       輸出結果:2.018000e+03   1.000000e-04  */
    
               
  • 以上的

    fixed

    setprecision()

    等,包括實作換行的

    endl

    ,都是流操縱算子

回到頂部

3. 流操縱算子

  • 借助輔助類,設定成員變量的類
  • 一些實作方式有在标準中定義,一些沒有,不同編譯器的實作不同
  • setprecision

    實作的示例:
    class setprecision {
    private:
        int precision;
    public:
        setprecision(int p): precision(p) {}
        friend class ostream;
    }
    
    class ostream {
    private:
        int precision;
    public:
        ostream& operator<< (const setprecision &m) {
            precision = m.precision;
            return *this;
        }
    } cout;
    
    cout << setprecision(2);
    // setprecision(2) 會構造一個 setprecision 類的對象,作為參數傳入輸出流的函數
               
  • endl

    實作的示例:
    class ostream {
        ......
        ostream& endl(ostream& os) {
            os.put('\n');     // 輸出換行符
            os.flush();       // 清空緩沖區
            return os;
        }
        ostream& operator<< (ostream& (*fn)(ostream&)) {
            return (*fn)(*this);
        }
    }
    
    // 換行方法1:調用輸出流+流操縱算子
    cout << endl;
    
    // 換行方法2:直接使用endl函數
    endl(cout);
               
    清空緩沖區的好處:減少外部讀寫次數、保證内容正确讀寫到檔案

回到頂部

4.

cout

對象的唯一性

  • 定義重載流運算符 / 使用

    cout

    的方式:
    1. 所有重載流運算符都會傳回引用

      ostream&

    2. ostream

      類的拷貝構造函數會手動進行删除
      ostream(const ostream& x) = delete;
      ostream(ostream&& x);
                 
  • 原因:
    1. 減少複制開銷
    2. 隻移動不複制,隻使用一個全局對象

      cout

      進行輸出
    3. 多個對象無法同步輸出狀态

回到頂部

B) 檔案輸入、輸出流

功能 補充說明

ifstream

檔案輸入流 從檔案中讀取資料

istream

的子類

在編譯期間已經解析完畢

性能較好,取代了

scanf

scanf

是有寫入非法記憶體的風險)

ofstream

檔案輸出流 将資料寫入檔案中

ostream

的子類

***

ifstream

ofstream

類似,以下以

ifstream

進行說明:

回到頂部

1. 基本使用方法

#include <fstream>
#include <iostream>
using namespace std;

int main() {
    // 打開普通文本檔案
    ifsream input("filename.txt");
    
    // 以二進制形式打開檔案
    ifstream input("filename.bin", ifstream::binary);
    
    // 確定檔案正确打開才進行操作
    if(input) { 
        ...
    }
    
    // 操作完畢,關閉檔案
    input.close();
    
    return 0;
}
           

回到頂部

2. 讀入常用操作

  • 判斷是否到了文末
    while(input) {
        ...
    }
               
  • 去除前導空格
    input >> ws;
               
  • 檢查下一個字元,如果到了文末就停止
    int c = input.peek();
    if(c == EOF) break;
               
  • 讀取
    int n;
    input >> n;
    
    string str;
    input >> str;
    getline(cin, str);
    
    ...
    
    char sentence[1000];    
    input.getline(sentence, 1000);
               

回到頂部

C) 字元串輸入、輸出流

1. 簡介

  • stringstream

    • iostream

      的子類
    • 在對象内維護一個 buffer,可以實作輸入和輸出
    • 流輸出函數:将資料寫入 buffer
    • 流輸入函數:從 buffer 讀入資料
  • 基本使用方法
    #include <sstream>
    using namespace std;
    
    int main() {
        stringstream ss;
     
        ss << "10";       // 将資料寫進 ss 的 buffer
        ss << "0 200";    // 會自動連接配接字元串
        
        int a, b;
        ss >> a >> b;     // 從 buffer 讀取資料,轉換成 int
        
        return 0;
    }
               

回到頂部

2. 對象内的 buffer

  • 暫存資料的空間,包含已讀取和未讀取的内容
  • 可以用

    ss.str()

    來傳回 buffer 内的内容(傳回類型:string)
    stringstream ss;
    ss << "10";      // buffer内有【10】
    ss << "0 200";   // buffer内有【100 200】
    
    int a, b;
    ss >> a;         // a = 100,buffer内有【100 200】
    ss >> b;         // b = 200,buffer内有【100 200】
    
    ss.str("");      // 清空 buffer
               
  • 從以上代碼可見,buffer 内的内容不會因為被讀取而減少
    • 有兩個指針在維護着:head 和 tail
    • head:指向最後一個内容(下一個位置就是寫入新内容的位置)
    • tail:指向待讀取的第一個元素
    • 所有 head 在 tail 的後面,head 和 tail 之間是未讀取的元素

回到頂部

3. 實作類型轉換

template<class outtype, class intype>
outtype convert(intype val) {
    static stringstream ss;  // 避免重複初始化
    ss.str("");              // 清空 buffer
    ss.clear();              // 清空狀态位
    ss << val;
    outtype result;          // 定義要轉換的類型的變量
    ss >> result;
    return result;           // 傳回轉換後的内容
}

// 使用
string str = convert<string>(921);
int num = convert<int>("122");
           

回到頂部

繼續閱讀