首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C 語言二進位檔案讀寫常見錯誤與除錯

     編輯:程式設計綜合問答

C 語言結構體二進位檔案讀寫:三大常見陷阱

程式碼看似正確,執行卻找不到檔案或內容異常,通常是路徑、權限、編碼三大問題。

原始程式碼分析

#include <stdio.h>
#define n 2
struct student { int number; char name[10]; int score; } stu[n];

void save() {
    FILE *fp;
    if ((fp = fopen("file1.dat", "w")) == NULL) {  // 問題 1:相對路徑
        printf("error"); return;
    }
    for (int i = 0; i < n; i++)
        if (fwrite(&stu[i], sizeof(struct student), 1, fp) != 1)
            printf("error");
    fclose(fp);
}

陷阱一:相對路徑與工作目錄

// 問題:fopen("file1.dat", "w") 相對於「目前工作目錄」
// Visual Studio 預設工作目錄 = 專案目錄 (含 .sln 檔處)
// 執行檔目錄 = x64/Debug/ 或 Debug/

// 解決方案 1:使用絕對路徑
FILE *fp = fopen("C:\\Data\\file1.dat", "wb"); // 注意雙反斜線或正斜線

// 解決方案 2:取得執行檔目錄動態組合
char path[MAX_PATH];
GetModuleFileName(NULL, path, MAX_PATH);
PathRemoveFileSpec(path);
PathAppend(path, "file1.dat");
FILE *fp = fopen(path, "wb");

陷阱二:二進位模式 vs 文字模式


// 錯誤:Windows 下 "w" 為文字模式,會將 \n 轉換為 \r\n
// 正確:二進位檔案必須用 "wb" / "rb"
FILE *fp = fopen("file1.dat", "wb"); // 寫入二進位
FILE *fp = fopen("file1.dat", "rb"); // 讀取二進位

陷阱三:Windows 7+ 寫入權限 (UAC)

// Program Files、System32、根目錄 需要管理員權限
// 解決方案:
// 1. 寫入使用者目錄:%USERPROFILE%\Documents\MyApp\
// 2. 使用 SHGetKnownFolderPath 取得正確路徑
// 3. 資訊清單要求管理員權限 (不建議常駐程式)

完整修正版程式碼

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h> // Windows API for path
#include <shlobj.h>  // SHGetKnownFolderPath

#define N 2

typedef struct {
    int number;
    char name[10];
    int score;
} Student;

Student stu[N];

void getAppDataPath(char *buffer, size_t size) {
    PWSTR documentsPath;
    SHGetKnownFolderPath(&FOLDERID_Documents, 0, NULL, &documentsPath);
    char narrowPath[MAX_PATH];
    WideCharToMultiByte(CP_UTF8, 0, documentsPath, -1, narrowPath, MAX_PATH, NULL, NULL);
    CoTaskMemFree(documentsPath);
    snprintf(buffer, size, "%s\\MyApp\\students.dat", narrowPath);
}

int main() {
    char filePath[MAX_PATH];
    getAppDataPath(filePath, sizeof(filePath));
    
    // 建立目錄
    char dirPath[MAX_PATH];
    strcpy(dirPath, filePath);
    PathRemoveFileSpec(dirPath);
    CreateDirectory(dirPath, NULL);
    
    // 輸入資料
    for (int i = 0; i < N; i++) {
        printf("Enter student %d (number name score): ", i+1);
        scanf("%d %9s %d", &stu[i].number, stu[i].name, &stu[i].score);
    }
    
    // 寫入二進位檔案
    FILE *fp = fopen(filePath, "wb");
    if (!fp) { perror("fopen"); return 1; }
    
    for (int i = 0; i < N; i++) {
        if (fwrite(&stu[i], sizeof(Student), 1, fp) != 1) {
            perror("fwrite");
            fclose(fp);
            return 1;
        }
    }
    fclose(fp);
    printf("Saved to: %s\n", filePath);
    
    // 驗證讀取
    fp = fopen(filePath, "rb");
    Student readStu;
    while (fread(&readStu, sizeof(Student), 1, fp) == 1) {
        printf("Read: %d, %s, %d\n", readStu.number, readStu.name, readStu.score);
    }
    fclose(fp);
    return 0;
}

關鍵檢查清單

  1. ✅ 使用 "wb"/"rb" 二進位模式
  2. ✅ 使用絕對路徑或標準使用者目錄
  3. ✅ 檢查 fopen、fwrite、fread 回傳值
  4. ✅ 結構體對齊:#pragma pack(1) 若需跨平台相容
  5. ✅ 字串欄位固定長度,避免指標序列化問題

二進位檔案操作看似簡單,細節決定成敗。養成完整錯誤檢查與路徑管理習慣。

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