二進制檔案以記憶體映像形式存放資料,無格式轉換,適合結構體陣列的整體讀寫。配合 fseek/rewind 移動檔案位置指標,可實現隨機存取——直接跳轉到任意記錄讀寫,而非順序掃描。
| 函數 | 原型 | 用途 |
|---|---|---|
fwrite | size_t fwrite(const void *ptr, size_t size, size_t count, FILE *fp) | 寫入 count 個大小為 size 的資料塊 |
fread | size_t fread(void *ptr, size_t size, size_t count, FILE *fp) | 讀取 count 個大小為 size 的資料塊 |
fseek | int fseek(FILE *fp, long offset, int whence) | 移動檔案位置指標 |
rewind | void rewind(FILE *fp) | 指標歸零(等價 fseek(fp, 0, SEEK_SET)) |
ftell | long ftell(FILE *fp) | 取得目前指標位移 |
fseek 定位詳解
fseek(fp, offset, whence);
| whence 常數 | 數值 | 含義 |
|---|---|---|
SEEK_SET | 0 | 從檔案開頭計算位移 |
SEEK_CUR | 1 | 從目前位置計算位移 |
SEEK_END | 2 | 從檔案結尾計算位移(負值向前) |
注意:offset 必須為 long,大檔案請用 100L 字面值後綴。二進制模式下位移精確對應位元組;文字模式因換行轉換會導致位移錯誤。
#include
#include
struct Student {
char name[20];
int id;
int age;
char addr[30];
};
int main(void) {
FILE *fp;
struct Student stu, *p = &stu;
int recNo;
// 1. 建立測試檔(5 筆資料)
fp = fopen("students.dat", "wb");
if (!fp) { perror("create"); return 1; }
for (int i = 1; i <= 5; ++i) {
sprintf(stu.name, "Student%d", i);
stu.id = 1000 + i;
stu.age = 18 + i;
sprintf(stu.addr, "Address %d", i);
fwrite(&stu, sizeof(stu), 1, fp);
}
fclose(fp);
// 2. 隨機讀取第 3 筆 (recNo=2, 0-based)
fp = fopen("students.dat", "rb");
if (!fp) { perror("open"); return 1; }
recNo = 2; // 第 3 筆
fseek(fp, recNo * sizeof(struct Student), SEEK_SET);
if (fread(p, sizeof(struct Student), 1, fp) != 1) {
puts("Read failed or EOF");
} else {
printf("Name: %s, ID: %d, Age: %d, Addr: %s\n",
p->name, p->id, p->age, p->addr);
}
fclose(fp);
return 0;
}
fflushfwrite 寫入緩衝區,滿或 fclose/fflush 才寫入磁碟fflush(fp) 強制刷新輸出緩衝區,清除輸入緩衝區fflush,防止異常終止導致資料遺失
// 寫入檢查
if (fwrite(&data, size, count, fp) != count) {
if (ferror(fp)) perror("Write error");
else if (feof(fp)) puts("Unexpected EOF");
}
// 讀取檢查
size_t n = fread(buf, size, count, fp);
if (n != count) {
if (feof(fp)) puts("EOF reached");
if (ferror(fp)) perror("Read error");
}
| 錯誤 | 後果 | 修正 |
|---|---|---|
文字模式 "r" 用 fseek | 位移計算錯誤 | 二進制模式 "rb"/"wb" |
offset 用 int 超過 2GB | 溢位定位錯誤 | 用 long 或 off_t (POSIX) |
結構體含指標直接 fwrite | 寫入指標值而非指向資料 | 序列化:展平指標資料或用專用格式 |
| 不同編譯器/平台直接交換二進制檔 | 對齊、位序、大小差異導致讀錯 | 定義打包結構 #pragma pack(1) 或用可移植格式 (JSON/Protobuf) |
fread/fwrite + fseek 構成 C 語言隨機存取二進制檔案的核心組合。掌握「二進制模式、結構體大小計算、位移定位、緩衝區刷新、錯誤檢查」五大要點,並注意跨平台相容性,即可構建高效的資料持久化層。