適用於結構體、陣列、任意記憶體區塊的高效讀寫,不做格式轉換,直接搬移位元組。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr:緩衝區位址 (讀入目標 / 寫出來源)。size:單一元素大小 (位元組)。nmemb:元素個數。
#include
#include
struct Student {
char name[10];
int num;
int age;
char addr[15];
} boya[2], boyb[2], *pp, *qq;
int main(void)
{
FILE *fp;
int i;
pp = boya; qq = boyb;
if ((fp = fopen("stu_list", "wb+")) == NULL) {
printf("Cannot open file"); getch(); return 1;
}
printf("\ninput data\n");
for (i = 0; i < 2; ++i, ++pp)
scanf("%9s%d%d%14s", pp->name, &pp->num, &pp->age, pp->addr);
pp = boya;
fwrite(pp, sizeof(struct Student), 2, fp); /* 一次寫 2 筆 */
rewind(fp);
fread(qq, sizeof(struct Student), 2, fp); /* 一次讀 2 筆 */
printf("\n\nname\tnum\tage\taddr\n");
for (i = 0; i < 2; ++i, ++qq)
printf("%s\t%5d\t%7d\t%s\n", qq->name, qq->num, qq->age, qq->addr);
fclose(fp);
getch();
return 0;
}
對應 printf/scanf,但目標為 FILE*。適合人類可讀的文字檔 (CSV、設定檔、日誌)。
int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
/* 寫入 */
for (i = 0, pp = boya; i < 2; ++i, ++pp)
fprintf(fp, "%s %d %d %s\n", pp->name, pp->num, pp->age, pp->addr);
/* 讀出 */
rewind(fp);
for (i = 0, qq = boyb; i < 2; ++i, ++qq)
fscanf(fp, "%9s %d %d %14s", qq->name, &qq->num, &qq->age, qq->addr);
| 維度 | fread/fwrite (二進位塊) | fprintf/fscanf (格式化文字) | fgetc/fputc/fgets/fputs (字元/行) |
|---|---|---|---|
| 檔案類型 | 二進位 ("rb"/"wb") | 文字 ("rt"/"wt") | 文字/二進位皆可 |
| 資料表達 | 記憶體原貌 (含 padding) | 人類可讀字串 | 字串/字元 |
| 跨平台可攜性 | 低 (端序、對齊、型別大小) | 高 (純文字) | 高 |
| 效能 | 最高 (無轉換) | 中 (格式解析/生成) | 中低 |
| 適用場景 | 高效能資料庫、影像、序列化 | 設定檔、CSV、日誌、除錯輸出 | 逐行處理、簡單文字 |
| 結構體直接存取 | 是 (一次寫整個 struct) | 需逐欄位 | 需逐欄位 |
sizeof(struct Student) 可能大於成員總和 (對齊 padding)。二進位檔跨平台讀取會失敗,僅限同編譯器/同架構。"%s %d" 會吞噬任意空白;"%s,%d" 則要求逗號分隔。pp++ 導致指標偏移,後續使用前必須 pp = boya; 重置。if (fread(...) != expected_count) { if (feof(fp)) ...; else ...; }"wt" 寫入 \n 會變 \r\n,讀入反向;二進位模式無轉換。