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

C語言二進制檔案隨機讀寫:fread/fwrite 與檔案定位實戰

     編輯:關於C語言

前言:二進制檔案與隨機存取

二進制檔案以記憶體映像形式存放資料,無格式轉換,適合結構體陣列的整體讀寫。配合 fseek/rewind 移動檔案位置指標,可實現隨機存取——直接跳轉到任意記錄讀寫,而非順序掃描。

一、核心函數

函數原型用途
fwritesize_t fwrite(const void *ptr, size_t size, size_t count, FILE *fp)寫入 count 個大小為 size 的資料塊
freadsize_t fread(void *ptr, size_t size, size_t count, FILE *fp)讀取 count 個大小為 size 的資料塊
fseekint fseek(FILE *fp, long offset, int whence)移動檔案位置指標
rewindvoid rewind(FILE *fp)指標歸零(等價 fseek(fp, 0, SEEK_SET))
ftelllong ftell(FILE *fp)取得目前指標位移

二、fseek 定位詳解


fseek(fp, offset, whence);
whence 常數數值含義
SEEK_SET0從檔案開頭計算位移
SEEK_CUR1從目前位置計算位移
SEEK_END2從檔案結尾計算位移(負值向前)

注意:offset 必須為 long,大檔案請用 100L 字面值後綴。二進制模式下位移精確對應位元組;文字模式因換行轉換會導致位移錯誤。

三、完整案例:學生資料隨機讀寫


#include 
#include 

struct Student {
    char name[20];
    int id;
    int age;
    char addr[30];
};

int main(void) {
    FILE *fp;
    struct Student stu, *p = &stu;
    int recNo;

    // 1. 建立測試檔(5 筆資料)
    fp = fopen("students.dat", "wb");
    if (!fp) { perror("create"); return 1; }
    for (int i = 1; i <= 5; ++i) {
        sprintf(stu.name, "Student%d", i);
        stu.id = 1000 + i;
        stu.age = 18 + i;
        sprintf(stu.addr, "Address %d", i);
        fwrite(&stu, sizeof(stu), 1, fp);
    }
    fclose(fp);

    // 2. 隨機讀取第 3 筆 (recNo=2, 0-based)
    fp = fopen("students.dat", "rb");
    if (!fp) { perror("open"); return 1; }

    recNo = 2;  // 第 3 筆
    fseek(fp, recNo * sizeof(struct Student), SEEK_SET);
    if (fread(p, sizeof(struct Student), 1, fp) != 1) {
        puts("Read failed or EOF");
    } else {
        printf("Name: %s, ID: %d, Age: %d, Addr: %s\n",
               p->name, p->id, p->age, p->addr);
    }
    fclose(fp);
    return 0;
}

四、緩衝區機制與 fflush

  • 標準 I/O 為全緩衝(檔案)或行緩衝(終端機)
  • fwrite 寫入緩衝區,滿或 fclose/fflush 才寫入磁碟
  • fflush(fp) 強制刷新輸出緩衝區,清除輸入緩衝區
  • 關鍵資料寫入後建議立即 fflush,防止異常終止導致資料遺失

五、錯誤檢查模式


// 寫入檢查
if (fwrite(&data, size, count, fp) != count) {
    if (ferror(fp)) perror("Write error");
    else if (feof(fp)) puts("Unexpected EOF");
}

// 讀取檢查
size_t n = fread(buf, size, count, fp);
if (n != count) {
    if (feof(fp)) puts("EOF reached");
    if (ferror(fp)) perror("Read error");
}

六、隨機存取應用場景

  • 大型資料庫索引:B+ 樹節點直接定位
  • 遊戲存檔:玩家狀態結構體隨機讀寫
  • 多媒體檔案:關鍵幀索引跳轉
  • 嵌入式配置區:特定位移寫入校準參數

七、常見錯誤

錯誤後果修正
文字模式 "r" 用 fseek位移計算錯誤二進制模式 "rb"/"wb"
offset 用 int 超過 2GB溢位定位錯誤用 long 或 off_t (POSIX)
結構體含指標直接 fwrite寫入指標值而非指向資料序列化:展平指標資料或用專用格式
不同編譯器/平台直接交換二進制檔對齊、位序、大小差異導致讀錯定義打包結構 #pragma pack(1) 或用可移植格式 (JSON/Protobuf)

結語

fread/fwrite + fseek 構成 C 語言隨機存取二進制檔案的核心組合。掌握「二進制模式、結構體大小計算、位移定位、緩衝區刷新、錯誤檢查」五大要點,並注意跨平台相容性,即可構建高效的資料持久化層。

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