C 語言檔案處理 (File I/O)
為了永久儲存資料(例如儲存遊戲存檔、記錄 log),我們需要使用檔案。C 語言透過 FILE 結構與一系列的標準函式庫來處理檔案讀寫。
基本檔案操作
1. 開啟檔案 (fopen)
// FILE *fopen(const char *filename, const char *mode);
FILE *fp = fopen("data.txt", "r");
操作模式 (Mode):
"r"(Read):讀取。檔案必須存在,否則回傳 NULL。"w"(Write):寫入。檔案若不存在會建立;若存在會清空 (Truncate) 內容。"a"(Append):追加。寫入的資料會接在原本內容後面。"r+":讀寫模式(檔案須存在)。"w+":讀寫模式(會清空檔案)。
永遠檢查
fopen 是否成功。如果 fp 是 NULL,代表開檔失敗(可能權限不足、硬碟滿了或檔案不存在)。2. 關閉檔案 (fclose)
fclose(fp);
操作完檔案後,一定要關閉,確保資料完整寫入硬碟緩衝區並釋放系統資源 (File Descriptor)。
文字檔讀寫 (Text I/O)
適合處理人類可讀的資料 (txt, csv, config)。
寫入 (fprintf)
用法跟 printf 幾乎一樣。
fprintf(fp, "Score: %d\n", 100);
讀取 (fscanf vs fgets)
- fscanf:適合讀取有固定格式的資料。
int score; fscanf(fp, "Score: %d", &score); - fgets:適合讀取一整行文字(更安全,推薦)。
char buffer[100]; while (fgets(buffer, sizeof(buffer), fp) != NULL) { printf("%s", buffer); }
二進位檔讀寫 (Binary I/O)
如果要儲存圖片、聲音、或是結構 (Struct) 資料,應該使用二進位模式。這樣可以確保資料原封不動地寫入,不會受到換行符號 (\n vs \r\n) 轉換的影響。
模式字串要加上 b,例如 "rb", "wb"。
寫入 (fwrite)
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
讀取 (fread)
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
範例:儲存陣列到檔案
#include <stdio.h>
int main() {
int data[] = {10, 20, 30, 40, 50};
// 1. 寫入二進位檔
FILE *fp = fopen("data.bin", "wb"); // 注意 "wb"
if (fp != NULL) {
// 寫入 5 個 int
fwrite(data, sizeof(int), 5, fp);
fclose(fp);
}
// 2. 讀取二進位檔
int read_data[5];
fp = fopen("data.bin", "rb"); // 注意 "rb"
if (fp != NULL) {
// 讀取回來
fread(read_data, sizeof(int), 5, fp);
fclose(fp);
}
return 0;
}
標準串流 (Standard Streams)
其實 printf 和 scanf 只是特例,它們分別是對以下標準檔案指標操作:
stdin(Standard Input):標準輸入(通常是鍵盤)。stdout(Standard Output):標準輸出(通常是螢幕)。stderr(Standard Error):標準錯誤輸出(通常也是螢幕)。
這意味著你可以用 fprintf(stdout, "Hello") 來取代 printf("Hello")。
技巧:發生錯誤時,請將錯誤訊息印到 stderr,而不是 stdout。這樣使用者在使用管線 (Pipeline) 重導向輸出時,錯誤訊息才不會被導到檔案裡。
if (fp == NULL) {
fprintf(stderr, "Fatal Error: Cannot open config file!\n");
return 1;
}
最佳實踐
- 總是檢查 fopen 的回傳值。
- 使用
perror或strerror:當開檔失敗時,這些函式可以告訴你「為什麼」失敗(例如:No such file or directory)。#include <errno.h> #include <string.h> // ... if (fp == NULL) { fprintf(stderr, "Error opening file: %s\n", strerror(errno)); } - 文字檔用文字模式,二進位檔用二進位模式:雖然在 Linux 上沒差,但在 Windows 上混用會導致換行符號錯亂。
掌握檔案處理,你的程式就能夠持久化資料,與作業系統進行更深度的互動。