C 語言文件操作遵循「打開 → 讀寫 → 關閉」生命週期,核心圍繞 FILE* 指針展開。本文系統整理高頻 API,附帶模式表、返回值檢查與典型用法。
FILE *fopen(const char *path, const char *mode);
返回:成功返回文件指針,失敗返回 NULL 並設置 errno。
模式組合:
| 基礎 | 含義 | 二進制 | 讀寫 | 行為 |
|---|---|---|---|---|
r | 只讀 | rb | r+/rb+ | 文件必須存在 |
w | 只寫 | wb | w+/wb+ | 截斷或創建 |
a | 追加 | ab | a+/ab+ | 定位末尾,創建或保留內容 |
關鍵差異:w截斷文件,a保留內容;+賦予讀寫雙向能力;b禁用換行轉換。
int fgetc(FILE *fp); // 讀取字符,EOF 表示結束/出錯
int fputc(int c, FILE *fp); // 寫入字符,返回寫入字符或 EOF
// 典型讀取循環
int ch;
while ((ch = fgetc(fp)) != EOF) {
process(ch);
}
getchar()/putchar() 分別等同於 getc(stdin)/putc(c, stdout)。
char *fgets(char *buf, int n, FILE *fp); // 讀取至 \n 或 n-1 字符,保留 \n
int fputs(const char *s, FILE *fp); // 寫入字符串(不含 \0)
// 典型逐行處理
char line[1024];
while (fgets(line, sizeof(line), fp)) {
// line 以 \0 結尾,可能包含 \n
}
fgets遇到\n會保留它,fputs不寫入\0。
int fprintf(FILE *fp, const char *fmt, ...); // 類似 printf
int fscanf(FILE *fp, const char *fmt, ...); // 類似 scanf
// 典型用法
while (fscanf(fp, "%s %d", name, &score) == 2) {
fprintf(stdout, "%s\t%d\n", name, score);
}
fscanf 成功返回匹配項數,失敗返回 EOF。
size_t fread(void *buf, size_t size, size_t count, FILE *fp);
size_t fwrite(const void *buf, size_t size, size_t count, FILE *fp);
b)打開文件int fseek(FILE *fp, long offset, int whence); // 返回 0 成功,非 0 失敗
long ftell(FILE *fp); // 返回當前偏移量,-1 表示錯誤
// whence 取值
#define SEEK_SET 0 // 文件開頭
#define SEEK_CUR 1 // 當前位置
#define SEEK_END 2 // 文件結尾
// 可移植的位置記錄/恢復
fpos_t pos;
fgetpos(fp, &pos); // 記錄
fsetpos(fp, &pos); // 恢復
fseek配合SEEK_END可獲取文件大小:fseek(fp, 0, SEEK_END); long size = ftell(fp);
int fclose(FILE *fp); // 關閉,刷新緩衝區
int remove(const char *pathname); // 刪除文件
int rename(const char *old, const char *new); // 重命名(文件需關閉)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
typedef struct {
char id[20];
char name[30];
float score;
} Student;
Student stu[MAX];
int count = 0;
void save(const char *filename) {
FILE *fp = fopen(filename, "wb");
if (!fp) { perror("打開失敗"); return; }
fwrite(&count, sizeof(int), 1, fp);
fwrite(stu, sizeof(Student), count, fp);
fclose(fp);
}
void load(const char *filename) {
FILE *fp = fopen(filename, "rb");
if (!fp) { perror("打開失敗"); return; }
fread(&count, sizeof(int), 1, fp);
fread(stu, sizeof(Student), count, fp);
fclose(fp);
}
while(!feof(fp)) → ✅ 用讀取函數返回值控制循環fwrite 結構體 → ✅ 必須用二進制模式fopen 失敗 → ✅ 永遠檢查返回值fflush/fseekmalloc 或靜態/全局存儲