HOWTO · C++
如何在 C++ 中寫入檔案
本文示範如何在 C++ 中寫入檔案。了解檔案串流和不同的檔案模式,並透過清晰的範例有效地管理 C++ 程式中的檔案操作。無論您需要附加資料還是覆寫現有內容,本指南都能幫到您。
本頁內容
一般文字輸出可使用 std::ofstream 搭配插入運算子(<<)寫入檔案。使用 std::ios::app 可將資料附加在檔案末尾;若要取代現有內容,則可使用 std::ios::trunc。若已知要寫入的字元或位元組數量,可使用串流的 write 成員函式;對應的 C 語言風格替代方案是 fwrite。
認識 C++ 檔案串流
檔案串流可讓 C++ 程式連接到指定名稱的檔案。加入 <fstream>,並建立 std::ofstream 來輸出;若同一個串流需要同時讀取與寫入,則使用 std::fstream。插入運算子適合輸出格式化文字,而字串中的換行字元會在檔案中開始新的一行。開啟檔案及寫入後都要檢查串流狀態,因為路徑看似有效,檔案仍可能無法存取,或儲存空間可能無法使用。
執行以下範例:
#include <fstream>
#include <iostream>
int main() {
std::ofstream file("example.txt");
if (!file) {
std::cerr << "Could not open example.txt\n";
return 1;
}
file << "Hello, C++!\n";
file << "File output is ready.\n";
file.close();
if (!file) {
std::cerr << "Could not finish writing example.txt\n";
return 1;
}
std::cout << "Wrote example.txt\n";
return 0;
}
Wrote example.txt
訊息會輸出到主控台;透過 file 寫入的兩行內容則會儲存在 example.txt。請用文字編輯器開啟該檔案,檢查其中內容。父目錄存在時,預設的純輸出 std::ofstream 會建立檔案;開啟時通常也會清除檔案原有內容。
以不同模式寫入檔案
開啟模式會決定如何處理檔案中的既有資料。std::ios::app 會讓每次寫入都從檔案末尾開始,適合用於需要累積內容的日誌或記錄。若檔案不存在,只要路徑與權限允許,以輸出模式開啟時就能建立檔案。以下獨立範例會以附加模式寫入一行內容,不需要事先建立 example.txt。
#include <fstream>
#include <iostream>
int main() {
std::ofstream file("example.txt", std::ios::app);
if (!file) {
std::cerr << "Could not open example.txt\n";
return 1;
}
file << "A new log entry\n";
file.close();
if (!file) {
std::cerr << "Could not finish writing example.txt\n";
return 1;
}
return 0;
}
提供的執行案例已成功完成,且沒有輸出主控台訊息。程式會寫入 A new log entry,並在後面加上換行;如果檔案已有內容,新的一行會接在原有內容後方。
使用 ios::trunc 寫入並覆寫檔案
開啟檔案時,std::ios::trunc 會捨棄檔案的原有內容。以輸出模式開啟 std::ofstream,且未使用 std::ios::app 時,通常也會有相同的截斷效果;若要明確表達這個選擇,可指定 std::ios::trunc。如果必須保留舊資料,請勿使用這兩種方式。
#include <fstream>
#include <iostream>
int main() {
std::ofstream file("example.txt", std::ios::trunc);
if (!file) {
std::cerr << "Could not open example.txt\n";
return 1;
}
file << "Current report\n";
file.close();
if (!file) {
std::cerr << "Could not finish writing example.txt\n";
return 1;
}
return 0;
}
提供的執行案例已成功完成,且沒有輸出主控台訊息。程式只會將 Current report 和一個換行寫入 example.txt,取代檔案原有的所有內容。
使用 fstream::write 寫入檔案
若資料已放在字元緩衝區中,而且長度已知,可使用串流成員函式 write。它接受字元指標及要寫入的字元數量;不會自動加入終止字元或換行。這個數量的型別是串流大小,因此傳入 data.size() 會寫入字串中儲存的字元,不包含結尾的 null 字元。呼叫後請檢查串流狀態,以偵測寫入是否失敗。如需了解介面,請參閱 cppreference 的 basic_ostream::write 文件。
#include <fstream>
#include <iostream>
#include <string>
int main() {
const std::string data = "C++ buffer data\n";
std::fstream file("buffer.txt", std::ios::out | std::ios::trunc);
if (!file) {
std::cerr << "Could not open buffer.txt\n";
return 1;
}
file.write(data.data(), static_cast<std::streamsize>(data.size()));
if (!file) {
std::cerr << "Could not write buffer.txt\n";
return 1;
}
file.close();
if (!file) {
std::cerr << "Could not finish writing buffer.txt\n";
return 1;
}
return 0;
}
提供的執行案例已成功完成,且沒有輸出主控台訊息。程式會將 data 中的字元寫入 buffer.txt;換行字元包含在字串內,但不會寫入結尾的 null 字元。
字元寫入與位元組寫入的區別在於資料是否會被格式化。插入運算子會把值轉換成文字,而 write 和 fwrite 則不加格式化地複製緩衝區中的位元組。但僅複製位元組並不能保證它們原封不動地寫入檔案:在文字模式下開啟的串流,在行尾格式不同的平台上仍可能轉換換行符,例如 Windows 在輸出時會把 \n 轉換為 \r\n。當確切的位元組很重要時,請以二進位模式開啟串流,例如使用 std::ios::out | std::ios::binary | std::ios::trunc,或向 fopen 傳入 "wb" 而不是 "w",這樣就不會發生任何轉換。
使用 C 語言的 fwrite 函式寫入檔案
若使用 C 語言風格的檔案 I/O,fwrite 會接受指標、元素大小、元素數量及 FILE*。它的回傳值是已寫入的元素數量;只有在每個元素大小為一時,這個數量才等於位元組數。請檢查回傳的數量,再關閉檔案並檢查 fclose 的結果,因為緩衝寫入期間發生的錯誤可能會在關閉時才出現。
#include <cstdio>
#include <cstring>
#include <iostream>
int main() {
const char data[] = "C file output\n";
const std::size_t size = std::strlen(data);
std::FILE* file = std::fopen("c-output.txt", "w");
if (file == nullptr) {
std::cerr << "Could not open c-output.txt\n";
return 1;
}
const std::size_t written = std::fwrite(data, 1, size, file);
const int close_status = std::fclose(file);
if (written != size || close_status != 0) {
std::cerr << "Could not finish writing c-output.txt\n";
return 1;
}
return 0;
}
提供的執行案例已成功完成,且沒有輸出主控台訊息。程式會將 data 中的字元(包含換行)寫入 c-output.txt;"w" 模式會建立檔案,或截斷檔案原有內容。
結論
一般文字輸出請使用 std::ofstream 和 <<。若要保留舊內容並從檔案末尾新增資料,請選擇 std::ios::app;若要取代舊內容,請選擇 std::ios::trunc。已知緩衝區長度時可使用 write;使用 C 語言風格的 I/O 時則可使用 fwrite。請檢查檔案是否成功開啟及寫入;如果程式需要確認資料已完整寫入,也要檢查關閉時是否發生錯誤。
常見問題
-
如何確認檔案是否成功開啟? 直接檢查串流(
if (!file)),或在開啟後立即呼叫is_open()。若開啟失敗,請先處理錯誤,再進行寫入。 -
如何附加內容而不取代檔案原有內容? 使用
std::ios::app開啟輸出串流。每次寫入都會指向檔案末尾。 -
C++ 會建立不存在的檔案嗎? 若父目錄存在且程式具有相應權限,輸出串流和使用
"w"模式的fopen都能建立檔案。父目錄不存在或權限不足時,開啟會失敗。 -
如何寫入多行內容? 使用
<<插入換行字元,或在傳給write的緩衝區中包含換行字元。write和fwrite都不會自動加入換行。 -
需要關閉檔案嗎? 檔案串流在物件銷毀時會自動關閉;明確呼叫
close()則能清楚標示操作完成的時點。若需要確認資料已寫入,請在關閉後檢查串流狀態。使用 C 的FILE*時,請呼叫fclose並檢查其回傳值。