| 模式 | 函數對 | 單位 | 適用場景 | 關鍵特性 |
|---|---|---|---|---|
| 字元 | fgetc/fputc | 1 字節 | 逐字元處理、簡單過濾 | 每次 1 字節,低效 |
| 字串 | fgets/fputs | 行/字串 | 文本行讀取、配置檔解析 | 遇 \n 停止,自動加 \0 |
| 塊 | fread/fwrite | 任意結構體 | 二進制序列化、結構體陣列 | 原始記憶體映射,高效 |
| 格式化 | fscanf/fprintf | 文本欄位 | 文本報表、日誌、CSV 類 | 人類可讀,自動型別轉換 |
int fputc(int ch, FILE* fp); // 成功返回寫入字元,失敗 EOF
int fgetc(FILE* fp); // 成功返回字元(0-255),失敗 EOF
關鍵細節:
fputc 只寫入 ch 低 8 位(ch & 0xFF)fgetc 返回 int 而非 char,必須用 int 接收 以區分有效 0xFF 與 EOF(-1)char 接收會誤判為 EOF
int fputs(const char* s, FILE* fp);
char* fgets(char* s, int n, FILE* fp); // 讀 n-1 字元或遇 \n 止,補 \0
關鍵行為:fgets 遇 \n 會將 \n 讀入緩衝區並停止。這是區分「空行」與「檔案結束」的關鍵。
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* fp);
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* fp);
size:單個元素大小(通常 sizeof(Struct))nmemb:元素個數fwrite 寫入必配 fread 讀取,勿混用格式化/字串函數
int fprintf(FILE* fp, const char* format, ...);
int fscanf(FILE* fp, const char* format, ...);
本質差異:格式化將 int 32768 寫為 5 字元 '3','2','7','6','8'(佔 5 字節),而塊寫入佔 4 字節原始二進制。格式化 = 型別轉字串 + 寫入。
typedef struct { char name[20]; double score; int age; } Student;
Student s1[3] = {{"liudehua",85.5,45},{"zhangxueyou",79.3,47},{"guofucheng",83.4,43}};
Student s2[3];
FILE* fp = fopen("test.txt", "wb+");
// 1. 塊寫入
fwrite(s1, sizeof(Student), 3, fp);
rewind(fp);
fread(s2, sizeof(Student), 3, fp); // 完美還原
// 2. 格式化寫入
for (int i=0;i<3;i++)
fprintf(fp, "%s %lf %d\n", s1[i].name, s1[i].score, s1[i].age);
rewind(fp);
for (int i=0;i<3;i++)
fscanf(fp, "%s %lf %d", s2[i].name, &s2[i].score, &s2[i].age);
// 3. 文本 vs 二進制模式差異
fprintf(fp, "%d", 32768); // 文本模式寫 5 字節 '3','2','7','6','8'
fwrite(&n, sizeof(int), 1, fp); // 二進制寫 4 字節 0x00 0x80 0x00 0x00
| 方式 | 檔案內容 | 大小 | 可讀性 |
|---|---|---|---|
| 塊寫入 | 原始記憶體映射(含結構體填充位元組) | 固定 | 不可讀 |
| 格式化 | 人類可讀文本(數字轉字元、含分隔符) | 可變 | 可讀 |
| 文本模式 | \n → \r\n (Windows) | 略大 | 可讀 |
| 二進制模式 | 位元組原樣 | 精確 | 不可讀 |
fgetc 必須用 int 接收fgets 會保留 \n,處理時需去除fread/fwrite 成對使用,結構體填充位元組會寫入檔案(跨平台/跨編譯器不兼容)fscanf 格式字串需精確匹配輸入,失敗會留下垃圾字元導致後續讀取錯位"wb"/"rb" 打開