1. 程式人生 > 實用技巧 >11_IO流與流類庫

11_IO流與流類庫

IO流與流類庫

IO流概念

流是資訊流動的一種抽象, 在程式中的物件、檔案物件 之間相互流動

流物件與檔案操作

  • 程式建立一個流物件
  • 指定這個流物件與某個檔案物件建立連線
  • 程式操作流物件
  • 流物件通過檔案系統對所連線的檔案物件產生作用。

提取與插入

  • 讀操作在流資料抽象中被稱為(從流中)提取
  • 寫操作被稱為(向流中)插入。

輸出流

三個輸出流

  • ostream
  • ofstream
  • ostringstream

三個輸出流物件

  • cout 標準輸出
  • cerr 標準錯誤輸出,沒有緩衝,傳送給它的內容立即被輸出。
  • clog 類似於cerr,但是有緩衝,緩衝區滿時被輸出。

標準輸出換向:預設是輸出到螢幕的

ofstream fout("b.out");
streambuf*  pOld  =cout.rdbuf(fout.rdbuf());  
//…
cout.rdbuf(pOld);

構造輸出流物件

ofstream myFile("filename");
//等價於
ofstream myFile; //宣告一個靜態檔案輸出流物件
myFile.open("filename");   //開啟檔案,使流物件與檔案建立聯絡
//指定開啟模式
ofstream myFile("filename", ios_base::out | ios_base::binary);

檔案輸出流成員函式

  • open函式, 把流與一個特定的磁碟檔案關聯起來。
    需要指定開啟模式。

  • put函式, 把一個字元寫到輸出流中。

  • write函式, 把記憶體中的一塊內容寫到一個檔案輸出流中

  • seekp和tellp函式, 操作檔案流的內部指標

  • close函式, 關閉與一個檔案輸出流關聯的磁碟檔案

  • 錯誤處理函式, 在寫到一個流時進行錯誤處理

向文字檔案輸出

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

int main() {    
    ofstream myFile("readme.txt");
	myFile << "hello" << "world" << endl;
	myFile << "huanxi" << endl;
    return 0;
}

向二進位制檔案輸出

二進位制

  • 儲存效率高

文字檔案

  • 存在一個文字到二進位制的轉換,效率較低
#include <fstream>
using namespace std;
struct Date { 
    int mon, day, year;  
};
int main() {
    Date dt = { 6, 10, 92 };
    ofstream file("date.dat", ios_base::binary);
    file.write(reinterpret_cast<char *>(&dt),sizeof(dt));
    file.close();
    return 0;
}

向字串輸出

向記憶體中給的字串輸出

  • 用於構造字串
  • 功能
    • 支援ofstream類的除open、close外的所有操作
    • str函式可以返回當前已構造的字串
  • 典型應用
    • 將數值轉換為字串
#include <iostream>
#include <sstream>
#include <string>
using namespace std;

//函式模板toString可以將各種支援“<<“插入符的型別的物件轉換為字串。

template <class T>
inline string toString(const T &v) {
    ostringstream os;   //建立字串輸出流
    os << v;        //將變數v的值寫入字串流
    return os.str();    //返回輸出流生成的字串
}

int main() {
    string str1 = toString(5);
    cout << str1 << endl;
    string str2 = toString(1.2);
    cout << str2 << endl;
    return 0;
}
輸出結果:
5
1.2

輸入流

輸入流類

  • istream類最適合用於順序文字模式輸入。cin是其例項。
  • ifstream類支援磁碟檔案輸入。
  • istringstream

構造輸入流物件

  • 如果在建構函式中指定一個檔名,在構造該物件時該檔案便自動開啟。 ifstream myFile("filename");
  • 在呼叫預設建構函式之後使用open函式來開啟檔案。 ifstream myFile; //建立一個檔案流物件 myFile.open("filename"); //開啟檔案"filename”
  • 開啟檔案時可以指定模式 ifstream myFile("filename", iosbase::in | iosbase::binary);

提取運算子從文字檔案輸入

  • 提取運算子(>>)對於所有標準C++資料型別都是預先設計好的,遇到空格結束
  • 是從一個輸入流物件獲取位元組最容易的方法。
  • ios類中的很多操縱符都可以應用於輸入流。但是隻有少數幾個對輸入流物件具有實際影響,其中最重要的是進位制操縱符dec、oct和hex。

相關函式

  • open 把該流與一個特定磁碟檔案相關聯。
  • get 功能與提取運算子(>>)很相像,主要的不同點是get函式在讀入資料時包括空白字元。
  • getline 功能是從輸入流中讀取多個字元,並且允許指定輸入終止字元,讀取完成後,從讀取的內容中刪除終止字元。
  • read 從一個檔案讀位元組到一個指定的記憶體區域,由長度引數確定要讀的位元組數。當遇到檔案結束或者在文字模式檔案中遇到檔案結束標記字元時結束讀取。
  • seekg 用來設定檔案輸入流中讀取資料位置的指標。
  • tellg 返回當前檔案讀指標的位置。
  • close 關閉與一個檔案輸入流關聯的磁碟檔案。
//get函式
#include <iostream>
using namespace std;
int main() {
    char ch;
    while ((ch = cin.get()) != EOF)
        cout.put(ch);
    return 0;
}
//輸入流指定一個終止字元
#include <iostream>
#include <string>
using namespace std;
int main() {
    string line;
    cout << "Type a line terminated by 't' " << endl; 
    getline(cin, line, 't');
    cout << line << endl;
    return 0;
}
//從檔案讀一個二進位制資料到結構體
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;

struct SalaryInfo {
    unsigned id;
    double salary;
}; 
int main() {
    SalaryInfo employee1 = { 600001, 8000 };
    ofstream os("payroll", ios_base::out | ios_base::binary);
    os.write(reinterpret_cast<char *>(&employee1), sizeof(employee1));
    os.close();
    ifstream is("payroll", ios_base::in | ios_base::binary);
    if (is) {
        SalaryInfo employee2;
        is.read(reinterpret_cast<char *>(&employee2), sizeof(employee2));
        cout << employee2.id << " " << employee2.salary << endl;
    } else {
        cout << "ERROR: Cannot open file 'payroll'." << endl;
    }
    is.close();
    return 0;
}
//seekg函式設定位置指標
int main() {
    int values[] = { 3, 7, 0, 5, 4 };
    ofstream os("integers", ios_base::out | ios_base::binary);
    os.write(reinterpret_cast<char *>(values), sizeof(values));
    os.close();

    ifstream is("integers", ios_base::in | ios_base::binary);
    if (is) {
        is.seekg(3 * sizeof(int));
        int v;
        is.read(reinterpret_cast<char *>(&v), sizeof(int));
        cout << "The 4th integer in the file 'integers' is " << v << endl;
    } else {
        cout << "ERROR: Cannot open file 'integers'." << endl;
    }
    ret
//讀一個檔案並顯示其中0元素位置
int main() {
    ifstream file("integers", ios_base::in | ios_base::binary);
    if (file) {
        while (file) {//讀到檔案尾file為0
            streampos here = file.tellg();
            int v;
            file.read(reinterpret_cast<char *>(&v), sizeof(int));
            if (file && v == 0) 
            cout << "Position " << here << " is 0" << endl;
        }
    } else {
        cout << "ERROR: Cannot open file 'integers'." << endl;
    }
    file.close();
    return 0;
}

從字串輸入流讀取

  • 用於從字串讀取資料
  • 在建構函式中設定要讀取的字串
  • 功能
    • 支援ifstream類的除open、close外的所有操作
  • 典型應用
    • 將字串轉換為數值
template <class T>
inline T fromString(const string &str) {
    istringstream is(str);  //建立字串輸入流
    T v;
    is >> v;    //從字串輸入流中讀取變數v
    return v;   //返回變數v
}

int main() {
    int v1 = fromString<int>("5");
    cout << v1 << endl;
    double v2 = fromString<double>("1.2");
    cout << v2 << endl;
    return 0;
}
輸出結果:
5
1.2
istringstream istr("5 1.2");
int a;
float b;
istr >> a >> b;

a=5, b=1.2

輸入輸出流

  • 一個iostream物件可以是資料的源或目的。
  • 兩個重要的I/O流類都是從iostream派生的,它們是fstream和stringstream。這些類繼承了前面描述的istream和ostream類的功能。

fstream類

  • fstream類支援磁碟檔案輸入和輸出。
  • 如果需要在同一個程式中從一個特定磁碟檔案讀並寫到該磁碟檔案,可以構造一個fstream物件。
  • 一個fstream物件是有兩個邏輯子流的單個流,兩個子流一個用於輸入,另一個用於輸出。

stringstream類

  • stringstream類支援面向字串的輸入和輸出
  • 可以用於對同一個字串的內容交替讀寫,同樣是由兩個邏輯子流構成。