| 函數 | 用途 |
|---|---|
fopen | 開啟檔案,指定模式(讀/寫)與類型(二進位/文字) |
fclose | 關閉已開啟檔案 |
fread | 讀取檔案 |
fwrite | 寫入檔案 |
fseek/fsetpos | 將檔案指標移至指定位置 |
ftell/fgetpos | 取得檔案指標目前位置 |
前四個函數適用於文字檔與隨機存取檔,後兩組專用於隨機存取。隨機存取意指可在檔案任意位置間切換讀寫,無須徹底讀完整個檔案。
二進位檔案為任意長度的位元組序列(0~255),位元組本身無特殊含義。相對地,文字檔中 13=CR、10=LF、26=EOF,讀取軟體需解析這些控制碼。現代術語中,二進位檔案視為位元組流,重點在資料流而非來源。C 語言中可視為檔案、資料流或長陣列,隨機存取即可讀寫陣列任意部分。
#include <stdio.h>
#include <string.h>
int main() {
const char *filename = "test.txt";
const char *mytext = "Once upon a time there were three bears.";
FILE *ft = fopen(filename, "wb"); // 二進位寫入模式
if (ft) {
fwrite(mytext, sizeof(char), strlen(mytext), ft);
fclose(ft);
}
printf("len of mytext = %d\n", (int)strlen(mytext));
return 0;
}
關鍵點:
wb 模式:檔案不存在則建立,存在則清空內容。fwrite 參數:緩衝區、元素大小、元素個數、檔案指標。二進位模式下不自動加入換行符,需自行在字串中包含。\"c:\\\\folder\\\\test.txt\"。| 模式 | 類型 | 讀 | 寫 | 建立 | 截斷 |
|---|---|---|---|---|---|
| r | 文字 | ✓ | |||
| rb | 二進位 | ✓ | |||
| r+ | 文字 | ✓ | ✓ | ||
| r+b / rb+ | 二進位 | ✓ | ✓ | ||
| w | 文字 | ✓ | ✓ | ✓ | |
| wb | 二進位 | ✓ | ✓ | ✓ | |
| w+ | 文字 | ✓ | ✓ | ✓ | ✓ |
| w+b / wb+ | 二進位 | ✓ | ✓ | ✓ | ✓ |
| a | 文字 | ✓ | ✓ | ||
| ab | 二進位 | ✓ | ✓ | ||
| a+ | 文字 | ✓ | ✓ | ✓ | |
| a+b / ab+ | 二進位 | ✓ | ✓ | ✓ |
經驗上,除非剛建立或讀完檔案,使用 w+b 較保險。Microsoft 延伸模式尚有 t(文字)、c(認可)、n(非認可)、S(循序優化)、R(隨機優化)、T(暫存)、D(刪除/暫存)。
資料庫普及前,隨機存取檔案常用於資料處理。小型檔案常採索引/資料雙檔案模式:
struct {
fpos_t pos; // 檔案位置
int size; // 記錄大小
} indexrec;
fpos_t 為 fsetpos/fgetpos 使用的型別,是 fseek/ftell 的改良版,更適合建立書籤。需計算檔案位置用 fseek,取得目前位置用 ftell(回傳 int)。實務上 fpos_t 可能只是 int,但應使用 fpos_t 型別,它保存檔案指標副本,粒度為 1,可定位至檔案任意位置。
// 寫入結構陣列到二進位檔案
struct Record { int id; char name[32]; double score; };
void WriteRecords(const char *filename, Record *recs, int count) {
FILE *fp = fopen(filename, "wb");
if (fp) {
fwrite(recs, sizeof(Record), count, fp);
fclose(fp);
}
}
// 隨機讀取第 n 筆記錄 (0-based)
bool ReadRecord(const char *filename, int n, Record *out) {
FILE *fp = fopen(filename, "rb");
if (!fp) return false;
fseek(fp, n * sizeof(Record), SEEK_SET);
bool ok = (fread(out, sizeof(Record), 1, fp) == 1);
fclose(fp);
return ok;
}