首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言文件操作完全指南:從基礎 API 到工程實踐

     編輯:關於C語言

前言

文件操作是 C 語言持久化存儲的核心能力。本文系統梳理 ANSI C 標準 I/O(FILE* 流)與 POSIX 低級 I/O(文件描述符)兩大體系,涵蓋打開模式、讀寫定位、錯誤處理、二進制/文本模式差異、緩衝機制及工程級最佳實踐。

一、標準 I/O(stdio.h)流操作

1. 文件打開與模式

FILE *fopen(const char *path, const char *mode);
模式含義文件需存在截斷可讀可寫追加二進制
r只讀是否✓✗✗文本
w寫入否是✗✓✗文本
a追加否否✗✓✓文本
r+讀寫是否✓✓✗文本
w+讀寫建新否是✓✓✗文本
a+讀寫追加否否✓✓✓文本
rb/wb/ab/rb+/wb+/ab+對應二進制模式-----二進制

關鍵差異:Windows 文本模式下 \n ⇄ \r\n 轉換;二進制模式無轉換。跨平台處理二進制數據**必須用二進制模式**。

2. 讀寫函數族

類別函數用途返回值
字符fgetc/fputc單字符讀寫字符/EOF
getc/putc宏版本,可能求值參數多次同上
getchar/putchar標準輸入/輸出專用同上
行fgets/fputs讀取/寫入一行(含換行)指針/EOF
gets/puts已棄用/移除(緩衝區溢出風險)-
格式化fprintf/fscanf格式化讀寫字符數/EOF
vfprintf/vfscanfva_list 版本同上
二進制塊fread/fwrite按大小/數量讀寫成功項數
feof/ferror/clearerr狀態檢查非零/零

3. 定位與緩衝控制

long ftell(FILE *stream);           // 當前位置
int fseek(FILE *stream, long offset, int whence); // 絕對/相對定位
int fsetpos(FILE *stream, const fpos_t *pos);     // 可移植定位(大文件)
void rewind(FILE *stream);            // 回到開頭
int fflush(FILE *stream);             // 強制刷新輸出緩衝
void setbuf(FILE *stream, char *buf); // 全緩衝/無緩衝
int setvbuf(FILE *stream, char *buf, int mode, size_t size); // 精細控制

whence:SEEK_SET 開頭、SEEK_CUR 當前、SEEK_END 結尾。

4. 錯誤處理模式

FILE *fp = fopen("data.bin", "rb");
if (!fp) {
    perror("fopen failed");  // 打印 errno 對應信息
    return -1;
}
if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) {
    if (feof(fp)) puts("Unexpected EOF");
    else if (ferror(fp)) perror("Read error");
}
fclose(fp); // 必須關閉,刷新緩衝、釋放資源

二、低級 I/O(unistd.h/fcntl.h)文件描述符

POSIX 系統調用接口,無用戶態緩衝,直接與內核交互。

核心 API

int open(const char *path, int flags, mode_t mode); // mode 僅創建時有效
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
off_t lseek(int fd, off_t offset, int whence);
int close(int fd);
int fsync(int fd);        // 強制寫入磁盤
int ftruncate(int fd, off_t length); // 截斷/擴展文件

常用 flags 組合

Flag含義
O_RDONLY / O_WRONLY / O_RDWR讀/寫/讀寫(必選一)
O_CREAT不存在則創建(需 mode)
O_TRUNC截斷至零長度
O_APPEND追加模式(原子寫入尾部)
O_EXCL與 O_CREAT 同用,存在則報錯
O_SYNC / O_DSYNC同步寫入(數據/元數據落盤)
O_NONBLOCK非阻塞模式
O_CLOEXECexec 時自動關閉(安全)

三、二進制 vs 文本、大端小端、跨平台持久化

1. 結構體直接讀寫陷阱

struct Record { int id; double val; char name[20]; };
// 直接 fwrite(&rec, sizeof(rec), 1, fp) 存在問題:
// - 填充字節不確定
// - 大小端不同機器不可讀
// - 指針字段無意義
// - 結構體版本演進不兼容

2. 序列化最佳實踐

  • 定長二進制協議:手動按字節序(網絡序 big-endian)寫入基本類型,結構體展開
  • 文本協議:JSON/CSV/Protobuf 文本格式,可讀、跨語言、版本兼容性好
  • 專用序列化庫:Protocol Buffers、FlatBuffers、MessagePack、CBOR

四、工程級最佳實踐清單

  1. 總是檢查返回值:fopen/fread/fwrite/fseek/close 等
  2. 資源獲取即初始化 (RAII) 模式:C 用 goto cleanup 或 __attribute__((cleanup)) 模擬
  3. 大文件支持:編譯加 -D_FILE_OFFSET_BITS=64,用 fseeko/ftello/off_t
  4. 原子寫入模式:寫臨時文件 + rename() 覆蓋,防止寫入中斷損壞數據
  5. 臨時文件安全:mkstemp()/tmpfile() 避免競爭條件
  6. 權限最小化:open 時 mode=0600,umask 配合
  7. 錯誤信息記錄:strerror(errno) 記錄上下文,便於事後分析

五、總結

C 語言文件操作雖接口樸素,但掌握緩衝機制、定位語義、錯誤處理、跨平台差異、序列化策略,才能構建健壯的存儲層。現代項目建議:業務邏輯用高級序列化庫,底層熱路徑用 mmap/IO_uring,標準 I/O 用於日誌/配置等非性能敏感場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved