在 C++ 要讀寫檔案,是將之連結至串流,基於串流的 I/O 架構與相關說明,可以在〈Input/output library〉找到。
在〈終端機輸入輸出〉中,談過 cout
是 ostream
實例,cin
是 istream
實例,這兩個實例是定義在 iostream
標頭。
istream
型態是定義在 istream
標頭,它是 basic_istream
模版類別的 basic_istream<char>
特化版本,basic_istream
是字元輸入串流的基礎模版類別;ostream
型態是定義在 ostream
標頭,它是 basic_ostream
模版類別的 basic_ostream<char>
特化版本,basic_ostream
是字元輸出串流的基礎模版類別。
在文字檔案串流的處理方面,basic_ifstream
繼承了 basic_istream
,而 ifstream
型態是 basic_ifstream<char>
特化版本,用來進行文字檔案輸入串流操作,basic_ofstream
繼承了 basic_ostream
,而 ofstream
型態是 basic_ofstream<char>
特化版本,用來進行文字檔案輸出串流操作,ifstream
、ofstream
定義在 fstream
標頭之中。
使用 ifstream
建立實例時,可以指定連結的檔案名稱,如果沒有指定檔案名稱,會建立一個沒有連結檔案的串流,後續必須以 open
來連結檔案:
void open( const char *filename,
ios_base::openmode mode = ios_base::in );
void open( const std::string &filename,
ios_base::openmode mode = ios_base::in );
例如,可以使用下面這個片段來開啟檔案輸入串流:
ifstream in;
in.open("filename");
如果開啟失敗,串流物件在布林判別場合會是 false
,可以使用下面的片段來判斷:
if(in) {
... 進行檔案處理
}
類似地,使用 ofstream
建立實例時,可以指定連結的檔案名稱,如果沒有指定檔案名稱,會建立一個沒有連結檔案的串流,後續必須以 open
來連結檔案:
void open( const char *filename,
ios_base::openmode mode = ios_base::out );
void open( const std::string &filename,
ios_base::openmode mode = ios_base::out );
mode
決定檔案的開啟模式,是由 ios
類別定義的常數來決定,下面列出 openmode
的值與用途:
ios::in
:輸入(basic_ifstream
預設)ios::out
:寫入(basic_ofstream
預設)ios::ate
:開啟後移至檔案尾端ios::app
:附加模式ios::trunc
:如果檔案存在,清除檔案內容ios::binary
:二進位模式
當然,程式的世界實際上並沒有文字檔案這東西,資料都是二進位,字元串流只是在讀取或寫入的過程,會進行文字編碼的轉換,例如 int
數字 9,在寫入的操作中,會轉換為編碼 57 的位元組資料,至於本身是 char
的資料,就直接以對應的位元組寫出。
因為 ifstream
、ofstream
各是 istream
、ostream
的子類別,>>
與 <<
運算子也可以用在 ifstream
、ofstream
實例上,結果就是使用 ifstream
、ofstream
時,可以如同使用 cin
、cout
一樣地操作。
來看個讀寫檔案的範例:
#include <iostream>
#include <fstream>
using namespace std;
struct Account {
string id;
string name;
double balance;
Account(string id = "", string name = "", double balance = 0.0) :
id(id), name(name), balance(balance) {};
};
void print(ostream &out, Account &acct) {
out << acct.id << " "
<< acct.name << " "
<< acct.balance;
}
void read(istream &in, Account &acct) {
in >> acct.id >> acct.name >> acct.balance;
}
int main() {
Account acct = {"123-456-789", "Justin Lin", 1000};
ofstream out("account.data");
print(out, acct);
out.close(); // 記得關閉檔案
Account acct2;
ifstream in("account.data");
read(in, acct2);
in.close(); // 記得關閉檔案
print(cout, acct2);
return 0;
}
因為 ifstream
、ofstream
各是 istream
、ostream
的子類別,cin
與 cout
也各是 istream
、ostream
實例,因此 print
、read
對它們來說是通用的,執行過後,account.data 檔案中會存有「123-456-789 Justin 0」,而最後標準輸出中,也會顯示「123-456-789 Justin 0」。