C 語言檔案寫入完整指南:從基礎到進階應用

1. 前言

在程式設計中,檔案的讀寫是非常重要的操作之一。在 C 語言中,檔案操作的基本流程包括開啟檔案、寫入資料以及關閉檔案。本文將重點介紹在 C 語言中進行檔案寫入的基礎方法與具體範例。

檔案寫入可用於資料持久化以及與其他程式共享資料,因此是許多程式中必備的重要技能。此外,透過學習 C 語言中的檔案操作,也能更容易理解其他程式語言的檔案處理方式。透過本文,您將學習從基本寫入方法到進階錯誤處理的內容,並加深對檔案操作的理解。

下一章將從檔案的開啟與關閉操作,以及寫入模式的基礎知識開始說明。

2. 檔案寫入的基礎

在 C 語言中進行檔案寫入前,必須先開啟檔案,並指定開啟的目的。C 語言使用 fopen 函數來開啟檔案,並使用 fclose 函數關閉檔案。以下將說明檔案開啟與關閉的基本操作,以及各種寫入模式。

fopen 函數的使用方法

要開啟檔案可使用 fopen 函數。該函數接受檔案名稱與模式(檔案操作類型)作為引數。基本語法如下:

FILE *fopen(const char *filename, const char *mode);
  • filename:要開啟的檔案名稱(或路徑)
  • mode:開啟檔案的模式(寫入、讀取、附加等)

寫入模式的種類

檔案開啟模式有多種,以下介紹與寫入相關的幾種:

  • "w":只寫模式。若檔案已存在,內容會被清除;若不存在,則建立新檔。
  • "a":附加模式。若檔案已存在,資料將附加到檔案末尾;若不存在,則建立新檔。
  • "wb":二進位寫入模式。若檔案已存在,內容會被清除並以二進位方式寫入;若不存在,則建立新檔。

寫入範例

以下示範建立新檔並寫入資料的程式碼。若檔案已存在,內容將被清除,並以 "w" 模式寫入。

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "w"); // 以 "w" 模式開啟檔案
    if (file == NULL) {
        printf("無法開啟檔案。\n");
        return 1;
    }

    fprintf(file, "您好,這是使用 C 語言寫入檔案的範例!\n");
    fclose(file); // 關閉檔案
    printf("檔案寫入完成。\n");

    return 0;
}

在此範例中,fopen 用來建立名為 “example.txt” 的檔案,並使用 fprintf 將文字資料寫入。寫入完成後,務必使用 fclose 關閉檔案,否則可能導致資料未正確保存。

fclose 函數的重要性

fclose 必須在開啟檔案後呼叫,用於釋放系統資源並確保資料正確儲存。若未關閉檔案就結束程式,可能導致寫入中斷,因此養成使用 fclose 的習慣非常重要。

下一章將更詳細介紹文字檔案的寫入方法。

3. 寫入文字檔的方法

在 C 語言中,將資料寫入文字檔有三種方式:以字元為單位、以字串為單位,以及格式化資料的方式。針對不同需求,可使用對應的函數。本節將介紹 fputcfputsfprintf 這三種寫入方式。

fputc 函數 — 寫入單一字元

fputc 用於一次寫入一個字元,適合需要逐字元處理的情況。語法如下:

int fputc(int character, FILE *stream);
  • character:要寫入的字元
  • stream:檔案指標

fputc 使用範例

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
        printf("無法開啟檔案。\n");
        return 1;
    }

    fputc('A', file); // 寫入 'A'
    fputc('B', file); // 寫入 'B'
    fputc('\n', file); // 寫入換行符

    fclose(file);
    printf("字元寫入完成。\n");

    return 0;
}

此範例將字元 'A''B' 分別寫入檔案,適合處理小規模的字元資料。

fputs 函數 — 寫入整個字串

fputs 可一次寫入整段字串,效率較高。語法如下:

int fputs(const char *str, FILE *stream);
  • str:要寫入的字串
  • stream:檔案指標

fputs 使用範例

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
        printf("無法開啟檔案。\n");
        return 1;
    }

    fputs("這是使用 fputs 寫入的範例。\n", file);

    fclose(file);
    printf("字串寫入完成。\n");

    return 0;
}

此範例一次將完整字串寫入檔案,適合批量寫入文字資料。

fprintf 函數 — 寫入格式化資料

fprintfprintf 的檔案版本,可依格式化輸出不同型別的資料。

int fprintf(FILE *stream, const char *format, ...);
  • stream:檔案指標
  • format:包含格式指定的字串

fprintf 使用範例

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
        printf("無法開啟檔案。\n");
        return 1;
    }

    int number = 123;
    float decimal = 45.67;
    fprintf(file, "整數: %d, 浮點數: %.2f\n", number, decimal);

    fclose(file);
    printf("格式化資料寫入完成。\n");

    return 0;
}

此範例使用 fprintf 將整數與浮點數以指定格式寫入檔案,非常適合輸出報表或結構化資料。

小結

fputcfputsfprintf 都能用於文字檔的寫入,依需求選擇合適的函數可提高效率與靈活性。下一章將介紹如何將資料寫入二進位檔案。

4. 寫入二進位檔的方法

C 語言不僅能處理文字檔,還能直接寫入二進位檔,例如圖片、音訊或結構體資料。這可透過 fwrite 完成。

fwrite 函數的使用方法

fwrite 會將記憶體中的資料原封不動地寫入檔案,不會進行文字轉換。

size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
  • ptr:資料的指標
  • size:單個元素的大小(位元組)
  • count:元素數量
  • stream:檔案指標

以二進位模式開啟檔案

寫入二進位檔時需使用 "wb""ab" 模式,確保資料不被轉換。

fwrite 寫入範例

#include <stdio.h>

int main() {
    FILE *file = fopen("example.bin", "wb");
    if (file == NULL) {
        printf("無法開啟檔案。\n");
        return 1;
    }

    int data[] = {10, 20, 30, 40, 50};
    size_t dataSize = sizeof(data) / sizeof(data[0]);

    fwrite(data, sizeof(int), dataSize, file);

    fclose(file);
    printf("二進位資料寫入完成。\n");

    return 0;
}

此範例將整數陣列直接以二進位格式寫入檔案,效率高且適合大量資料處理。

二進位檔的注意事項

  • 資料相容性:二進位資料在不同系統間可能無法正確讀取。
  • 位元組序(Endianness):不同架構的位元組序不同,跨平台需進行轉換。
  • 換行處理:二進位模式下換行符不會自動轉換,資料將原封不動保存。

小結

二進位檔寫入適用於需要完整保留原始資料的情況,例如圖片或結構體。使用 fwrite 可有效率地保存資料。下一章將介紹檔案操作中的錯誤處理方法。

5. 錯誤處理(Error Handling)

在進行檔案操作時,可能因檔案不存在、權限不足等原因導致錯誤。妥善處理這些錯誤,可避免程式出現異常行為並提升可靠性。本節將介紹在 C 語言中進行檔案操作時的錯誤處理方法。

檔案開啟時的錯誤檢查

當檔案不存在或權限不足時,fopen 會回傳 NULL。透過檢查此值即可判斷檔案是否開啟成功。

檔案開啟錯誤檢查範例

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "r");
    if (file == NULL) {
        perror("無法開啟檔案");
        return 1;
    }

    // 檔案處理程式碼
    fclose(file);

    return 0;
}

此範例中,當 fopen 失敗時,使用 perror 輸出錯誤訊息,可快速得知錯誤原因。

perrorstrerror 顯示錯誤訊息

  • perror:將自訂訊息與系統錯誤原因一併輸出到標準錯誤輸出(stderr)。
  • strerror:接收錯誤代碼並回傳對應的錯誤訊息字串。

strerror 使用範例

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

int main() {
    FILE *file = fopen("nonexistent.txt", "r");
    if (file == NULL) {
        printf("錯誤: %s\n", strerror(errno));
        return 1;
    }

    fclose(file);
    return 0;
}

此範例使用 errno 取得最近一次錯誤的代碼,並透過 strerror 轉換為可讀訊息。

偵測與處理寫入錯誤

在寫入檔案時,也可能發生錯誤,可用 ferror 檢查檔案流是否有錯誤。

寫入錯誤檢查範例

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
        perror("無法開啟檔案");
        return 1;
    }

    if (fprintf(file, "寫入資料") < 0) {
        perror("寫入錯誤發生");
        fclose(file);
        return 1;
    }

    fclose(file);
    printf("寫入完成。\n");

    return 0;
}

此範例檢查 fprintf 的回傳值,若小於 0 代表寫入失敗,並輸出錯誤訊息。

小結

在檔案操作中實作錯誤處理,可提升程式的安全性與穩定性。包括檢查檔案開啟結果、使用錯誤訊息函數以及檢測寫入錯誤等,都是必備的處理方式。

6. 應用範例

掌握檔案寫入基礎後,我們可以將其應用在實際開發中,例如紀錄日誌、產生設定檔、資料序列化與反序列化等。

寫入日誌檔

日誌檔可用來記錄程式執行狀態與錯誤,方便除錯與追蹤。

日誌寫入範例

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

void log_message(const char *message) {
    FILE *file = fopen("log.txt", "a");
    if (file == NULL) {
        perror("無法開啟日誌檔");
        return;
    }

    time_t now = time(NULL);
    struct tm *t = localtime(&now);

    fprintf(file, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n",
            t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
            t->tm_hour, t->tm_min, t->tm_sec, message);

    fclose(file);
}

int main() {
    log_message("程式已啟動。");
    log_message("發生錯誤。");

    return 0;
}

此範例使用附加模式 "a" 開啟檔案,保留舊資料並新增新的日誌內容。

產生設定檔

設定檔可保存應用程式的配置,方便啟動時讀取。

設定檔寫入範例

#include <stdio.h>

void save_settings(const char *filename, int volume, int brightness) {
    FILE *file = fopen(filename, "w");
    if (file == NULL) {
        perror("無法開啟設定檔");
        return;
    }

    fprintf(file, "volume=%d\n", volume);
    fprintf(file, "brightness=%d\n", brightness);

    fclose(file);
}

int main() {
    save_settings("settings.conf", 75, 50);
    printf("設定檔已儲存。\n");

    return 0;
}

設定檔以「鍵=值」的格式保存,方便讀取與修改。

資料序列化與反序列化

序列化可將資料結構直接儲存到檔案中,之後再讀取回記憶體。

結構體序列化範例

#include <stdio.h>

typedef struct {
    int id;
    char name[50];
    float score;
} Student;

void save_student(const char *filename, Student *student) {
    FILE *file = fopen(filename, "wb");
    if (file == NULL) {
        perror("無法開啟檔案");
        return;
    }

    fwrite(student, sizeof(Student), 1, file);
    fclose(file);
}

void load_student(const char *filename, Student *student) {
    FILE *file = fopen(filename, "rb");
    if (file == NULL) {
        perror("無法開啟檔案");
        return;
    }

    fread(student, sizeof(Student), 1, file);
    fclose(file);
}

int main() {
    Student s1 = {1, "佐藤太郎", 89.5};
    save_student("student.dat", &s1);

    Student s2;
    load_student("student.dat", &s2);
    printf("ID: %d, 姓名: %s, 分數: %.2f\n", s2.id, s2.name, s2.score);

    return 0;
}

此範例將結構體以二進位方式儲存與讀取,確保資料格式完全一致。

小結

透過日誌、設定檔與資料序列化的範例,可理解檔案寫入在實際專案中的應用方式。

7. 常見問題(FAQ)

以下整理了初學者在使用 C 語言進行檔案寫入時常見的問題與解決方法,幫助您快速排解檔案操作上的疑慮。

檔案無法開啟時怎麼辦?

Q: fopen 開檔失敗,該怎麼處理?

A:fopen 回傳 NULL,請檢查以下幾點:

  1. 檔案路徑是否正確:確認檔案實際位置與程式使用的路徑一致。
  2. 存取權限:確定檔案具有讀寫權限。
  3. 磁碟空間:若磁碟空間不足,可能無法建立新檔。
  4. 使用錯誤輸出:透過 perrorstrerror 輸出錯誤訊息以方便除錯。

寫入後檔案內容沒有更新

Q: 資料已寫入,但檔案內容沒有改變?

A: 可能原因如下:

  1. 忘記呼叫 fclose:檔案未關閉可能導致資料留在緩衝區未寫入磁碟。
  2. 需要立即更新:可呼叫 fflush(file); 強制將緩衝資料寫入。
  3. 作業系統快取延遲:有些系統會延遲寫入,檢查檔案前可重新整理檔案檢視器。

二進位檔與文字檔有什麼不同?

Q: 兩者差在哪裡?

A:

  • 文字檔:以純文字儲存,系統可能會轉換換行符號(Windows 使用 \r\n,UNIX/Linux 使用 \n)。
  • 二進位檔:原始位元資料直接儲存,不做任何轉換,適合圖片、音訊、結構體等。

寫入時出現錯誤

Q: 使用 fprintffwrite 時發生錯誤該怎麼辦?

A:

  1. 使用 ferror 檢查檔案流是否發生錯誤。
  2. 透過 perror 輸出詳細錯誤訊息。
  3. 確認磁碟空間是否足夠。
  4. 檢查檔案開啟模式是否允許寫入。

二進位檔跨平台讀取錯亂

Q: 讀取不同系統寫入的二進位檔出現亂碼或數值錯誤?

A: 這可能是位元組序(Endianness)不同造成的。

  1. 在儲存時使用 htonshtonl 等函數統一成網路位元組序。
  2. 檔案中保存位元組序資訊,讀取時依據該資訊轉換。

小結

透過檢查權限、正確關閉檔案、使用錯誤處理函數與注意位元組序,可解決大部分檔案寫入問題。

8. 總結

本文由淺入深介紹了 C 語言的檔案寫入,包括:

  • 使用 fopenfclose 開啟/關閉檔案的基礎操作。
  • fputcfputsfprintf 寫入文字檔。
  • 使用 fwrite 寫入二進位資料及注意事項。
  • 檔案操作錯誤處理技巧(perrorstrerrorferror)。
  • 應用範例:日誌、設定檔、資料序列化。
  • 常見問題與解決方法。

掌握這些技巧,不僅能在 C 語言中靈活操作檔案,也能更容易遷移到其他語言的檔案處理開發中。

建議讀者在實作中多嘗試不同寫入模式與錯誤處理方式,以提升程式的穩定性與可維護性。

年収訴求