所有檔案操作始於 fopen、終於 fclose。正確掌握開啟模式、錯誤檢查、資源釋放,是健壯檔案 I/O 的基石。
fopen 完整參數表
FILE *fopen(const char *filename, const char *mode);
| 模式 | 含義 | 檔案須存在 | 可讀 | 可寫 | 建立新檔 | 截斷現有 | 定位 |
|---|---|---|---|---|---|---|---|
"r" | 讀取文字 | 是 | ✓ | 開頭 | |||
"w" | 寫入文字 | 否 | ✓ | ✓ | ✓ | 開頭 | |
"a" | 附加文字 | 否 | ✓ | ✓ | 結尾 | ||
"r+" | 讀寫文字 | 是 | ✓ | ✓ | 開頭 | ||
"w+" | 建立讀寫文字 | 否 | ✓ | ✓ | ✓ | ✓ | 開頭 |
"a+" | 開啟/建立附加讀寫 | 否 | ✓ | ✓ | ✓ | 結尾 | |
"rb" | 讀取二進制 | 是 | ✓ | 開頭 | |||
"wb" | 寫入二進制 | 否 | ✓ | ✓ | ✓ | 開頭 | |
"ab" | 附加二進制 | 否 | ✓ | ✓ | 結尾 | ||
"rb+"/"r+b" | 讀寫二進制 | 是 | ✓ | ✓ | 開頭 | ||
"wb+"/"w+b" | 建立讀寫二進制 | 否 | ✓ | ✓ | ✓ | ✓ | 開頭 |
"ab+"/"a+b" | 開啟/建立附加讀寫二進制 | 否 | ✓ | ✓ | ✓ | 結尾 |
關鍵差異:b 模式無換行轉換(Windows \r\n↔\n),位移精確對應位元組,隨機存取必須用二進制模式。
// 錯誤:反斜線被視為跳脫字元
fopen("C:\TC\TEST.DAT", "r");
// 正確:雙反斜線或正斜線
fopen("C:\\TC\\TEST.DAT", "r");
fopen("C:/TC/TEST.DAT", "r"); // 跨平台建議
fclose 與錯誤處理標準模式
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
perror("fopen failed"); // 印出系統錯誤訊息
return -1; // 或 exit(EXIT_FAILURE)
}
// ... 檔案操作 ...
if (fclose(fp) != 0) {
perror("fclose failed");
// 注意:fclose 失敗時 fp 已不可用,不可再次 fclose
}
fp = NULL; // 防止懸空指標
#include
#include
int main(void) {
FILE *fp = fopen("CLIB", "rb");
if (fp == NULL) {
perror("Cannot open CLIB");
return EXIT_FAILURE;
}
int ch;
while ((ch = fgetc(fp)) != EOF)
putchar(ch);
if (fclose(fp) != 0)
perror("Close failed");
else
puts("File closed successfully");
return EXIT_SUCCESS;
}
CONFIG.SYS 中 FILES=n 設定同時開啟檔案上限(預設較小,如 8-20)freopen 重新導向標準串流
freopen("output.log", "w", stdout); // 之後 printf 寫入檔案
freopen("input.dat", "r", stdin); // 之後 scanf 從檔案讀取
常用於批次測試、日誌記錄。
| 錯誤 | 徵兆 | 修正 |
|---|---|---|
未檢查 fopen 返回值 | 後續操作崩潰 | 永遠 if (fp == NULL) |
模式字串錯誤(如 "rw") | 開啟失敗 | 嚴格對照模式表 |
| 路徑跳脫字元錯誤 | 找不到檔案 | 雙反斜線或正斜線 |
| 文字模式做隨機存取 | 位移錯誤 | 改用 b 模式 |
忘記 fclose | 資料遺失、檔案鎖定、洩漏 | 配對 fopen/fclose,或用 atexit 註冊清理 |
fopen/fclose 是檔案 I/O 的大門。熟記「模式字串對照表、路徑跳脫、NULL 檢查、fclose 返回值檢查、二進制模式配合隨機存取」五大鐵律,並將錯誤處理模式內化為肌肉記憶,即可避開 90% 的檔案操作坑。