文件 I/O 是 C 語言持久化數據的核心手段。本文通過一個完整示例,演示文本模式格式化讀寫、二進制模式結構體批量讀寫、動態內存配合文件操作的標準流程與錯誤處理。
| 函數 | 用途 | 模式 |
|---|---|---|
fopen | 打開文件,返回 FILE* | "r"/"w"/"a"/"rb"/"wb"/"ab" |
fclose | 關閉文件,刷新緩衝區 | — |
fprintf/fscanf | 格式化文本讀寫 | 文本 |
fread/fwrite | 二進制塊讀寫 | 二進制 |
fputc/fgetc | 單字符讀寫 | 文本 |
feof/ferror | 檢查結束/錯誤狀態 | — |
#include
#include
#define N 2
typedef struct {
char Class[20];
int age;
char name[9];
} Student;
int main() {
FILE *fp;
int i, n;
char Class[20], name[9];
int age;
/* === 1. 文本模式:寫入固定條數學生記錄 === */
printf("將學生信息寫入文本文件:\n");
fp = fopen("E:\\c\\stu.txt", "w");
if (!fp) { perror("fopen write"); return 1; }
for (i = 0; i < N; i++) {
printf("學生班級: "); scanf("%19s", Class);
printf("學生年齡: "); scanf("%d", &age);
printf("學生姓名: "); scanf("%8s", name);
fprintf(fp, "%s %6d %10s\n", Class, age, name);
}
fclose(fp);
/* === 2. 文本模式:讀取並顯示 === */
printf("\n從文本文件讀取學生信息:\n");
fp = fopen("E:\\c\\stu.txt", "r");
if (!fp) { perror("fopen read"); return 1; }
for (i = 0; i < N; i++) {
if (fscanf(fp, "%19s %d %8s", Class, &age, name) != 3) break;
printf("班級:%s, 年齡:%d, 姓名:%s\n", Class, age, name);
}
fclose(fp);
/* === 3. 二進制模式:動態分配結構體數組,追加寫入 === */
printf("\n向二進制文件追加學生信息:\n");
fp = fopen("E:\\c\\stu.dat", "wb"); // wb 截斷重寫,ab 則追加
if (!fp) { perror("fopen wb"); return 1; }
printf("追加記錄數: "); scanf("%d", &n);
Student *students = (Student*)malloc(sizeof(Student) * n);
if (!students) { perror("malloc"); fclose(fp); return 1; }
for (i = 0; i < n; i++) {
printf("第 %d 筆 - 班級: ", i+1); scanf("%19s", students[i].Class);
printf("第 %d 筆 - 年齡: ", i+1); scanf("%d", &students[i].age);
printf("第 %d 筆 - 姓名: ", i+1); scanf("%8s", students[i].name);
}
// 批量寫入:返回成功寫入的元素個數
if (fwrite(students, sizeof(Student), n, fp) != n) {
fprintf(stderr, "文件寫入失敗!\n");
}
fclose(fp);
free(students);
/* === 4. 二進制模式:讀取並顯示 === */
printf("\n從二進制文件讀取學生信息:\n");
fp = fopen("E:\\c\\stu.dat", "rb");
if (!fp) { perror("fopen rb"); return 1; }
// 重新分配內存接收數據
students = (Student*)malloc(sizeof(Student) * n);
if (!students) { perror("malloc"); fclose(fp); return 1; }
if (fread(students, sizeof(Student), n, fp) != n) {
fprintf(stderr, "文件讀取失敗或數據不全!\n");
} else {
for (i = 0; i < n; i++) {
printf("班級:%s, 年齡:%d, 姓名:%s\n",
students[i].Class, students[i].age, students[i].name);
}
}
fclose(fp);
free(students);
return 0;
}
\r\n ↔ \n),適合配置、日志、CSV。#pragma pack)、結構體定義必須完全一致。htonl/ntohl)。malloc/calloc)。fread/fwrite 返回值**必須檢查**,確認實際處理元素數。free,避免洩漏。fp = fopen(path, "rb");
if (!fp) { perror("fopen"); return -1; } // perror 自動打印 errno 信息
if (fread(buf, size, count, fp) != count) {
if (feof(fp)) fprintf(stderr, "意外到達文件末尾\n");
else if (ferror(fp)) perror("fread");
else fprintf(stderr, "數據不完整\n");
}
將學生信息寫入文本文件:
學生班級: Class1
學生年齡: 20
學生姓名: Alice
學生班級: Class2
學生年齡: 21
學生姓名: Bob
從文本文件讀取學生信息:
班級:Class1, 年齡:20, 姓名:Alice
班級:Class2, 年齡:21, 姓名:Bob
向二進制文件追加學生信息:
追加記錄數: 2
第 1 筆 - 班級: Class3
第 1 筆 - 年齡: 22
第 1 筆 - 姓名: Carol
第 2 筆 - 班級: Class4
第 2 筆 - 年齡: 23
第 2 筆 - 姓名: Dave
從二進制文件讀取學生信息:
班級:Class3, 年齡:22, 姓名:Carol
班級:Class4, 年齡:23, 姓名:Dave
掌握文本/二進制雙模式、結構體序列化邊界條件、動態內存安全配合,即可應對絕大多數 C 語言文件持久化場景。