許多 C++ 開發者習慣沿用 C 的 FILE* 指標操作檔案,這不僅影響程式碼美觀,也錯失了 C++ 標準庫提供的更完善、型別安全、物件導向的檔案操作機制。本文系統介紹 <fstream> 的核心用法。
| 類別 | 標頭檔 | 功能 |
|---|---|---|
| ifstream | <fstream> | 檔案讀取(輸入) |
| ofstream | <fstream> | 檔案寫入(輸出) |
| fstream | <fstream> | 同時支援讀寫 |
// 兩步驟:宣告再開啟
ifstream infile;
infile.open("data.txt");
// 一步驟:建構函數直接開啟
ifstream infile("data.txt");
ofstream outfile("output.txt", ios::out | ios::trunc);
if (!infile) { /* 開啟失敗處理 */ }
// 或
if (infile.fail()) { ... }
ofstream outfile("text.txt");
outfile << "Hello " << 123 << '\n'; // 寫入
ifstream infile("text.txt");
string word;
infile >> word; // 讀取以空白分隔的單字
| 操縱子 | 功能 | 適用 |
|---|---|---|
| dec / hex / oct | 十/十六/八進制輸出 | 輸入/輸出 |
| setprecision(n) | 浮點數精度位數 | 輸出 |
| endl | 換行並刷新緩衝區 | 輸出 |
| ends | 輸出空字元 \0 | 輸出 |
outfile << hex << 123; // 輸出 7b
outfile << setprecision(5) << 3.1415926; // 輸出 3.1416
string line;
getline(infile, line); // 讀至換行,捨棄換行字元
getline(infile, line, '|'); // 自訂分隔符
outfile.put('c'); // 寫入單一字元
char ch;
infile.get(ch); // 讀取單一字元到 ch
int c = infile.get(); // 返回字元整數值,EOF 為 -1
infile.get(buf, 100, '\n'); // 讀入字元陣列
// 寫入結構體陣列
struct Record { int id; double value; } recs[10];
outfile.write(reinterpret_cast<char*>(recs), sizeof(recs));
// 讀回
infile.read(reinterpret_cast<char*>(recs), sizeof(recs));
二進位模式下資料以位元組序列處理,不進行字元轉換,適合結構體、陣列等非文字資料。
// 讀取位置
infile.seekg(0, ios::beg); // 移至開頭
infile.seekg(10, ios::cur); // 從目前位置前移 10 位元組
infile.seekg(-20, ios::end); // 從末尾倒退 20 位元組
streampos pos = infile.tellg(); // 取得目前讀取位置
// 寫入位置
outfile.seekp(0, ios::beg);
streampos wpos = outfile.tellp();
注意:定位通常用於二進位檔案;文字檔案因換行字元轉換可能導致位置不符預期。
| 模式 | 含義 |
|---|---|
| ios::in | 讀取模式開啟 |
| ios::out | 寫入模式開啟(預設清空檔案) |
| ios::app | 每次寫入前移至檔案尾 |
| ios::ate | 開啟後定位於檔案尾 |
| ios::trunc | 開啟時清空現有內容 |
| ios::binary | 二進位模式 |
// 常見組合
ofstream ofs("log.txt", ios::out | ios::app); // 追加寫入
fstream fs("data.bin", ios::in | ios::out | ios::binary); // 讀寫二進位
ofstream 預設 ios::out | ios::trunc;ifstream 預設 ios::in。
infile.close(); // 程式結束或重新關聯其他檔案前必須關閉
善用 RAII:串流物件離開作用域時自動呼叫 close(),建議在區塊內使用串流物件以確保資源釋放。