C++檔案讀寫

範中豪發表於2021-05-23

本文主要用於探討使用C++來進行檔案讀寫操作。

在C++中,所有的輸入輸出操作大部分都繼承自 ios_base 基類,詳細的繼承體系如下圖所示

fstream的使用

在fstream類中,成員函式open()實現開啟檔案的操作,從而將資料流和檔案進行關聯,通過ofstream,ifstream,fstream物件進行對檔案的讀寫操作,同時在開啟檔案時,可以指定開啟的模式,如讀、寫或者讀寫,可選模式如下

mode detail
ios::in 為輸入(讀)而開啟檔案
ios::out 為輸出(寫)而開啟檔案
ios::ate 初始位置:檔案尾
ios::app 所有輸出附加在檔案末尾
ios::trunc 如果檔案已存在則先刪除該檔案
ios::binary 二進位制方式

open的定義方式

void open(const wchar_t *_Filename, 
    ios_base::openmode mode= ios_base::in | ios_base::out;

void open(const wchar_t *_Filename, 
    ios_base::openmode mode= ios_base::in | ios_base::out, 
    int prot = ios_base::_Openprot);

其中,filename表示操作檔名,mode表示開啟檔案的方式,prot表示開啟檔案的屬性。在開啟檔案時,在stream類的建構函式中呼叫open()函式都有自己預設的操作方式

ofstream out("...", ios::out);  
ifstream in("...", ios::in);  
fstream foi("...", ios::in|ios::out); 

使用write()read()函式進行檔案讀寫

int main(){
    string file_path = "test.txt";
    char info[] = "hello fan";
    char buffer[256];
    ofstream out(file_path, ios::binary);
    if(out.is_open()){
        out.write(info, sizeof(info));
        out.close();
    }
    ifstream in(file_path, ios::binary);
    if(in.is_open()){
        while(!in.eof()){
            in.read(buffer, 100);
            cout << buffer << endl;
        }
        in.close();
    }

    return 0;
}
// out
/*
hello fan
*/

ofstream過載了 <<操作符可用來向檔案輸出資料,ifstream過載了>>操作符,可用來讀入資料。

#include <iostream>
#include<fstream>
#include<string>

using namespace std;

int main(){
    string file_path = "test.txt";
    char buffer[256];
    ofstream out(file_path);
    if(out.is_open()){
        out << "hello ";
        out << "fan";
        out.close();
    }
    ifstream in(file_path);
    if(in.is_open()){
        while(!in.eof()){
            in.getline(buffer, 100);
            cout << buffer << endl;
        }

    }
    return 0;
}
// hello fan

在上述程式碼中,使用is_open()函式,用來判斷檔案是否正常開啟,eof()函式用來判斷是否讀到檔案末尾。

除了這些以外,還有一些驗證流的狀態的成員函式(所有都返回bool型返回值):

  • bad()
    如果在讀寫過程中出錯,返回 true 。例如:當我們要對一個不是開啟為寫狀態的檔案進行寫入時,或者我們要寫入的裝置沒有剩餘空間的時候。

  • fail()
    除了與bad() 同樣的情況下會返回 true 以外,加上格式錯誤時也返回true ,例如當想要讀入一個整數,而獲得了一個字母的時候。

  • good()
    這是最通用的:如果呼叫以上任何一個函式返回true 的話,此函式返回 false 。

為了能夠更為方便地對檔案進行操作,還需要能夠判斷我們讀檔案讀到了哪裡,使用函式tellg/tellp 用於提取當前檔案指標的位置,使用函式 seekg/seekp 來將檔案指標移到某處

  • tellg() 和 tellp()
    這兩個成員函式不用傳入引數,返回pos_type 型別的值(根據ANSI-C++ 標準) ,就是一個整數,代表當前get 流指標的位置 (用tellg) 或 put 流指標的位置(用tellp).

  • seekg() 和seekp()
    這對函式分別用來改變流指標get 和put的位置。兩個函式都被過載為兩種不同的原型:

seekg ( pos_type position ); 
seekp ( pos_type position );

使用這個原型,流指標被改變為指向從檔案開始計算的一個絕對位置。要求傳入的引數型別與函式 tellg 和tellp 的返回值型別相同。

seekg ( off_type offset, seekdir direction ); 
seekp ( off_type offset, seekdir direction );

使用這個原型可以指定由引數direction決定的一個具體的指標開始計算的一個位移(offset)。它可以是:

type detail
ios::beg 從流開始位置計算的位移
ios::cur 從流指標當前位置開始計算的位移
ios::end 從流末尾處開始計算的位移

示例

int main(){
    string file_path = "test.txt";
    char buffer[256];
    ifstream in(file_path);
    if(in.is_open()){
        auto site = in.tellg();
        in.seekg(site+6, ios::cur);
        while(!in.eof()){
            in.getline(buffer, 100);
            cout << buffer << endl;
        }

    }
    return 0;
}

上述檔案中資料為 "hello fan",輸出為 "fan",因為開始時,檔案指標指向檔案開頭,使用tellg()函式獲取檔案指標位置,然後使用seekg()函式將檔案指標後移6個字元,因此讀取結果為 "fan"。

簡單檔案讀寫示例

#include <iostream>
#include<fstream>
#include<string>

using namespace std;

int choose_mod(){
    int f = 0;
    cout << "----Easy file read and write----" << endl;
    cout << "Please choose write or read file" << endl;
    cout << "Enter 1, read file" << endl;
    cout << "Enter 2, write file" << endl;
    cout << "Enter 3, exit" << endl;
    cout << "--------------------------------" << endl;
    cin >> f;
    while(f != 1 && f != 2 && f != 3){
        cout << "Please choose 1 or 2 or 3" << endl;
        cin >> f;
    }

}

int main(){
    string file_name = "test.txt";
    int mod = choose_mod();
    char buffer[256];
    ifstream in;
    ofstream out;
    string tmp;

    while(mod != 3){
        if(mod == 1){
            in.open(file_name);
            if(in.is_open()){
                while(!in.eof()){
                    in.getline(buffer, 100);
                    cout << buffer << endl;
                }
                in.close();
            }
        }else{
            out.open(file_name, ios::app);
            if(out.is_open()){
                cout << "Please enter string, Enter quit end" << endl;
                tmp = "";
                while(true){
                    getline(cin, tmp);
                    if(tmp == "quit") break;
                    out << tmp << "\n";
                }
                out.close();
            }
        }
        mod = choose_mod();
    }
    cout << "Quit" << endl;

    return 0;
}

參考文獻

C++檔案讀寫詳解
C++檔案讀寫操作總結

相關文章