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

C 文件操作實戰:寫入統計信息到文件頭的高效方案

     編輯:關於C

業務場景

文本文件存儲多字段記錄(用戶|產品|價格...),字段間用 | 分隔。需求:文件第一行始終保存「總記錄數|總費用和」,每次追加記錄前更新首行統計。

核心難點

文件頭覆寫需精確控制文件指針:
1. 讀取/計算新統計值
2. rewind(fp) 定位文件開頭
3. 寫入新統計行(長度可能變化)
4. fseek(fp, 0, SEEK_END) 定位文件末尾
5. 追加新記錄

完整代碼實現

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    char Inf[3][20] = {0};
    char strs[3][10];
    int i = 0, iFeeSum = 0, iCount = 0, index = 0;
    char lz_Recond[20] = {0}, temp[20] = {0};

    // 模擬三條記錄:用戶|產品|費用
    strcpy(Inf[0], "you|90002|100\n");
    strcpy(Inf[1], "me|90003|100\n");
    strcpy(Inf[2], "she|90004|100\n");

    FILE *fp = fopen("Record.txt", "w");
    if (!fp) { printf("Can not open file\n"); exit(-1); }

    while (i < 3) {
        strcpy(temp, Inf[i]);
        char *p = strtok(temp, "|");
        while (p) {
            strcpy(strs[index++], p);
            p = strtok(NULL, "|");
        }

        iFeeSum += atoi(strs[2]);  // 累加費用(第 3 字段)
        iCount++;                  // 記錄條數 +1
        index = 0;

        // 格式化統計行:總費用|總記錄數
        sprintf(lz_Recond, "%d|%d\n", iFeeSum, iCount);
        printf("lz_Recond=%s", lz_Recond);

        rewind(fp);                    // 指針移至文件頭
        fputs(lz_Recond, fp);          // 覆寫統計行
        fseek(fp, 0, SEEK_END);        // 指針移至文件末尾
        fputs(Inf[i], fp);             // 追加新記錄
        i++;
    }
    fclose(fp);
    return 0;
}

關鍵函數解析

函數作用注意事項
rewind(fp)等價 fseek(fp, 0, SEEK_SET),清除錯誤標誌必須在寫入前調用,否則寫入位置不確定
fseek(fp, 0, SEEK_END)定位文件末尾追加模式 "a" 自動定位,但此處需手動控制
strtok按分隔符分割字符串破壞原字符串,故先 strcpy 到 temp

潛在問題與改進

⚠ 統計行長度變化導致數據覆蓋/殘留
若新統計行比舊行短(如 99|9 → 100|10),舊行尾部字符殘留;若更長,會覆蓋緊隨其后的第一條記錄。
解決方案:
1. 固定統計行寬度(sprintf(buf, "%-10d|%-10d\n", sum, cnt))
2. 或採用「讀全量→內存修改→全量覆寫」模式(文件較小時)
3. 或將統計信息單獨存儲於元數據文件/數據庫

改進版:固定寬度統計行

// 統計行固定 20 字節:費用(10) + '|' + 記錄數(10) + '\n'
sprintf(lz_Recond, "%-10d|%-10d\n", iFeeSum, iCount);
// 寫入前確保文件最小長度
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
if (fsize < 20) {
    char pad[20] = {0};
    fseek(fp, 0, SEEK_SET);
    fputs("          |         \n", fp);  // 佔位
    fseek(fp, 0, SEEK_END);
}
// 正常覆寫流程
rewind(fp);
fputs(lz_Recond, fp);
fflush(fp);  // 強制刷新緩衝區
fseek(fp, 0, SEEK_END);
fputs(Inf[i], fp);

生產環境建議

  • 採用 SQLite / Redis / 時序數據庫 替代文本文件,原生支持聚合查詢
  • 若必須用文本,考慮 WAL(預寫日誌) 模式:僅追加,定期重構索引
  • 多進程/線程並發寫入需加文件鎖(flock/fcntl)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved