《UNIX 環境高級編程》(APUE)是系統程式設計的經典教材。本文作為學習系列第一篇,重點整理文件 I/O 相關核心概念與標準 I/O 函數族的使用細節,所有內容基於 Linux 環境驗證。
標準 I/O 庫為每個打開的流維護一個文件位置指針,自動記錄下一次讀寫位置。程式員無需手動管理,但理解其機制對掌握 fseek、ftell、rewind 等定位函數至關重要。
open/read/write),性能高,但可移植性較差。fopen — 打開流FILE *fopen(const char *path, const char *mode);
常用模式:
| 模式 | 說明 |
|---|---|
r | 唯讀,指針指向文件首,文件必須存在 |
r+ | 讀寫,指針指向文件首,文件必須存在 |
w | 唯寫,不存在則創建,存在則截斷為 0,指針指向文件首 |
w+ | 讀寫,創建/截斷規則同 w |
a | 追加寫入,不存在則創建,指針指向文件尾 |
a+ | 讀取與追加,讀指針指向文件首,寫入總在文件尾 |
返回 FILE* 指針,失敗返回 NULL 並設 errno。
fclose — 關閉流int fclose(FILE *fp);
釋放資源,刷新緩衝區。使用後指針失效,切勿再次解引用。
fgets — 讀取字符串char *fgets(char *s, int size, FILE *stream);
從流讀取最多 size-1 字符,遇 \n、EOF 或錯誤停止,自動補 \0。返回 s 或 NULL。比 gets 安全,但仍可能截斷長行。
fread/fwrite — 二塊數據讀寫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);
關鍵點:返回值是成功讀寫的對象個數,而非字節數。習慣用 size=1, nmemb=N 逐字節讀寫,避免最後一個對象不完整導致計數偏差。
atoi 族 — 字符串轉整數int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
跳過前導空白,轉換連續數字字符,遇非數字停止。若首字符非數字返回 0。無錯誤檢測機制,生產代碼建議用 strtol。
printf 族 — 格式化輸出返回值:成功輸出的字符數(不含 \0)。
snprintf 安全格式化:
int snprintf(char *str, size_t size, const char *format, ...);
最多寫入 size-1 字符,強制以 \0 結尾,防止緩衝區溢出。可用於數字轉字符串、多字符串拼接。
scanf 族 — 格式化輸入警告:%s 無長度限制,極易導致緩衝區溢出。讀取用戶輸入請改用 fgets + sscanf 或手動解析。
fseek/ftell/rewind — 流定位int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);
whence:SEEK_SET(文件首)、SEEK_CUR(當前)、SEEK_END(文件尾)。
局限:參數/返回值為 long,僅支援 ±2GB。大文件請用 fseeko/ftello(POSIX,需 _POSIX_C_SOURCE)。
rewind(stream) 等價 fseek(stream, 0L, SEEK_SET) 並清除錯誤標誌。
getline — 動態讀取整行ssize_t getline(char **lineptr, size_t *n, FILE *stream);
自動分配/擴展緩衝區,無長度限制。GNU 擴展,編譯需 -D_GNU_SOURCE 或代碼開頭 #define _GNU_SOURCE。攜帶性要求高的項目建議自行封裝。
標準 I/O 函數族是 C 語言文件操作的基石。掌握緩衝模式、返回值語義、錯誤處理與大文件支援細節,能顯著提升代碼健壯性與可移植性。下一篇將探討系統級 I/O 與文件元數據操作。