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

C語言二進制文件讀寫時間結構體實踐與常見錯誤分析

     編輯:關於C語言

需求場景

程序首次運行時提示「首次運行」,否則讀取上次運行的時間並顯示;隨後將當前時間寫入文件,供下次讀取。核心涉及 time_t 與 struct tm 的二進制序列化/反序列化。

原代碼問題剖析

// 原代碼關鍵片段
void get_data(void) {
    time_t t;
    if ((fp = fopen(data_file, "r")) == NULL)  // 錯誤1:文本模式打開二進制文件
        printf("首次運行!\n");
    else {
        fread(&t, sizeof(time_t), 1, fp);      // 讀取時間戳
        struct tm *local;
        time(&t);                                // 錯誤2:覆蓋剛讀取的歷史時間!
        local = localtime(&t);
        printf(...);
        fclose(fp);
    }
}

void put_data(void) {
    time_t t;
    if ((fp = fopne(data_file)) == NULL)       // 錯誤3:拼寫錯誤 fopne → fopen
        printf("文件打開失敗\n");
    else {
        fwrite(&t, sizeof(time_t), 1, fp);     // 錯誤4:t 未初始化,寫入垃圾值
        fclose(fp);
    }
}

四大致命錯誤詳解

編號錯誤類型代碼位置後果修正方案
1文件模式錯誤fopen(..., "r")Windows下換行符轉換導致二進制數據損壞使用 "rb" / "wb" 模式
2邏輯倒置讀取後調用 time(&t)歷史時間被當前時間覆蓋,失去持久化意義直接用讀取的 t 轉換 localtime
3函數拼寫fopne編譯報錯/鏈接失敗修正為 fopen
4未初始化變量fwrite(&t, ...)寫入棧垃圾數據,下次讀取時間亂碼寫入前調用 time(&t) 獲取當前時間

修正後的完整實現

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

#define DATA_FILE "datetime.dat"

void get_data(void) {
    FILE *fp = fopen(DATA_FILE, "rb");
    if (fp == NULL) {
        printf("程序首次運行!\n");
        return;
    }

    time_t last_time;
    if (fread(&last_time, sizeof(time_t), 1, fp) != 1) {
        printf("讀取時間數據失敗!\n");
    } else {
        struct tm *local = localtime(&last_time);
        printf("上次運行時間:%04d-%02d-%02d %02d:%02d:%02d\n",
               local->tm_year + 1900, local->tm_mon + 1, local->tm_mday,
               local->tm_hour, local->tm_min, local->tm_sec);
    }
    fclose(fp);
}

void put_data(void) {
    FILE *fp = fopen(DATA_FILE, "wb");
    if (fp == NULL) {
        fprintf(stderr, "無法創建數據文件!\n");
        return;
    }

    time_t now;
    time(&now);                      // 先獲取當前時間
    fwrite(&now, sizeof(time_t), 1, fp); // 再寫入
    fclose(fp);
}

int main(void) {
    get_data();   // 讀取並顯示歷史時間
    put_data();   // 更新為當前時間
    return 0;
}

進階考量:跨平台與健壯性

  1. time_t 可移植性:C 標準未規定 time_t 大小/編碼(可能是 32/64 位整數或浮點數)。跨平台交換建議序列化為 ISO 8601 字符串或定長結構體(年/月/日/時/分/秒)。
  2. 錯誤處理:生產代碼應檢查 fread/fwrite 返回值,處理文件截斷、權限不足等異常。
  3. 併發安全:多進程訪問時需文件鎖(flock/LockFileEx)防止數據競爭。
  4. 備選方案:嵌入式系統常用 RTC 硬件時鐘,或將時間存儲於非易失性存儲(EEPROM/Flash)。

總結

本例暴露了初學者常見的四類錯誤:文件模式誤用、邏輯順序顛倒、拼寫疏忽、未初始化讀寫。二進制文件操作核心原則:模式匹配(rb/wb)、讀寫對稱、變量初始化、錯誤檢查。掌握這些,才能寫出可靠的持久化代碼。

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