C語言自學攻略-文件操作(檔案處理)全解析

更新 發佈閱讀 15 分鐘

檔案的輸入與輸出

在C語言中,我們使用FILE指標來開啟檔案:

FILE* fptr;

現在假設我們在主程式同一目錄下有一個message.txt文件,內容如下:

raw-image

接著,我們可以使用內建fopen函式來開啟文件。

fptr = fopen("message.txt", "r");
  • 開啟檔案意味著將我們的程式與該檔案連接起來。現在,我們可以對message.txt文件執行不同的文件操作
  • 其中,fopen函式的第二個參數"r" 表示已閱讀模式開啟了文件,這意味著我們只能執行讀取的操作。

而當我們開啟文件時,我們需要確保文件確實存在於指定位置,否則該fopen函式將會回傳NULL 。另一個該注意的點,是每當開啟文件後,在最後程式結束前,要記得使用fclose()來關閉文件,這是一個好習慣,以下示範:

#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
fp = fopen("message.txt","r")
if ( fp == NULL )
printf("檔案開啟失敗 \n");
else
printf("檔案開啟OK \n");
fclose(fp);
return 0;
}

打開文件後,我們可以使用fgets()函式讀取其內容,以下示範:

#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
fp = fopen("message.txt","r");
char content[100]; //用來儲存文件內容
if ( fp == NULL )
printf("檔案開啟失敗 \n");
else{
fgets(content, 100, fp); // fp 是用於讀取文件的文件指針
printf("%s", content);
}
fclose(fp);
return 0;
}
raw-image
  • 上圖是程式碼運行後得到的輸出結果,但是,我們只輸出了一行,並沒有輸出所有的文件內容,這是因為fgets()函數一次讀取一行。

因此,要讀取文件的所有內容,我們可以使用迴圈循環,以下示範:

#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
fp = fopen("message.txt","r");
char content[100]; //用來儲存文件內容
if ( fp == NULL )
printf("檔案開啟失敗 \n");
else{
while(fgets(content, 100, fp)){
printf("%s", content);
}
}
fclose(fp);
return 0;
}
raw-image
  • while迴圈以fgets() 函式做為循環的條件,該fgets()函數逐行讀取檔案內容並將其儲存在content字串中。如果讀取成功,則條件變為真並列印。
  • 但是,如果函式遇到檔案結束符(End-of-File),則傳回 NULL,條件變為 false,從而終止迴圈。所以有別於前一次輸出,這次輸出了完整的內容。

好,如果現在我們想要將內容寫入文件中,該怎麼做?

要將內容寫入文件,我們必須使用寫入模式來開啟文件,我們以"w"作為函式fopen()的第二個參數,並且使用fputs()函式將內容寫入文件。以下示範:

#include <stdio.h>

int main() {

FILE* fp;
fp = fopen("message.txt", "w");

fputs("I like you\n", fp); //使用換行符號
fputs("I love you", fp);

fclose(fp);

return 0;
}
  • 如果我們嘗試開啟一個不存在的文件,則會建立一個新文件。
  • 如果檔案已存在,則其內容將被刪除,並將新內容新增至該檔案。
raw-image
  • 可以看到,內容被重新寫入了。

那今天我們不想刪除原本的內容,而是想將新寫入的內容附加到原本的文件,我們改以"a"作為函式fopen()的第二個參數。以下示範:

#include <stdio.h>

int main() {

FILE* fp;
fp = fopen("message.txt", "a");

fputs(" so much", fp);

fclose(fp);

return 0;
}
  • 如果我們嘗試將內容附加到不存在的文件中,則會建立一個新文件。
  • 如果檔案已存在,則會將附加資料附加到檔案結尾,而不刪除先前的資料。
raw-image

剛才我們都是存取和程式碼同一目錄下的文件,假設你想存取外部文件的話,必須提供目錄及文件名稱,現在假設我們要存取一外部文件,而這文件位於 test_content 的目錄下,我們透過提供程式文件的路徑來存取文件內容,以下示範:

#include <stdio.h>

int main() {

FILE* fp;

fp = fopen("D:/test_content/messages.txt", "w");

fputs("I love C!", fp);

fclose(fp);

return 0;
}

現在你已經學會基本的讀寫文件了,不過,除了上面的操作之外,其實還有幾種讀取與寫入的幾種方式,下面一一介紹。

getc : 讀取一個字元

首先,在介紹讀取或寫入單個字元前,我先介紹feof()函式,這裡我順便提一下argcargv*[] 如何使用,我們以一個計算字元數的程式示範如何使用,不同於以往,這次我們要在終端機編譯並執行程式:

#include <stdio.h>

int main(int argc, char *argv[])
{
FILE *fp; // 定義檔案指標,用於指向要開啟的檔案
int count = 0; // 用來計算檔案的字元數
char ch; // 用於存放讀取的字元

if (argc != 2) // 檢查指令行參數是否正確,應該包含程式名和檔案名兩個參數
{
printf("指令錯誤 "); // 如果指令行參數數量不正確,輸出錯誤提示
return 1; // 結束程式,返回錯誤代碼 1
}

fp = fopen(argv[1], "r"); // 嘗試以讀取模式("r")開啟指令行指定的檔案
if (fp == NULL) // 如果檔案開啟失敗
{
printf("無法開啟檔案"); // 使用 `perror` 輸出具體的錯誤資訊
return 1; // 結束程式
}

// 讀取檔案,直到檔案末尾
while (!feof(fp)) // 檢查檔案是否到達末尾
{
ch = getc(fp); // 使用 `getc` 讀取檔案中的一個字元
count++; // 每次讀取有效字元後,計數器加 1
}

printf("%s檔案的字元數是 %d\n", argv[1], count); // 輸出檔案名稱和字元數

fclose(fp); // 關閉檔案,釋放資源

return 0;
}
  • 我們需要在終端機輸入以下指令來編譯程式並執行:
gcc your_program.c -o your_program

// 本程式的情況
gcc file_handling.c -o file_handling // 生成可執行檔案 file_handling.exe
//接著,我們輸入以下指令來運行
./file_handling.exe message.txt
  • argc 是指令行參數的個數。
  • argv 是指令行參數的各個字串陣列,其中:
    • argv[0] 是運行程式的指令(第一個字串)。
    • argv[1] 是使用者提供的檔案名(第二個字串)。

假設message.txt 的內容如下:

Hello World!
I love C!
  • 則程式輸出結果為 12 + 1 (換行符 ) + 10 = 23

Ok, 接著介紹寫入單個字元,我們撰寫一個程式來將message.txt的內容寫入到另一個文件file.txt中。

putc : 讀取一個字元

#include <stdio.h>

int main() {
FILE *source, *destination;
char ch;

// 打開 source 文件 message.txt,讀取模式
source = fopen("message.txt", "r");
if (source == NULL) {
printf("無法打開 message.txt");
return 1;
}

// 打開 destination 文件 file.txt,寫入模式
destination = fopen("file.txt", "w");
if (destination == NULL) {
printf("無法打開 file.txt");
fclose(source);
return 1;
}

// 從 source 文件中逐字元讀取,並寫入到 destination 文件中
while ((ch = getc(source)) != EOF) { //我們也可以這樣確認是否讀到檔案尾端
putc(ch, destination);
}

printf("Successfully copied from message.txt to file.txt");

// 關閉文件
fclose(source);
fclose(destination);

return 0;
}
  • 程式執行完畢後,你應該能在相同目錄下看到file.txt ,並且內容式複製過後的內容。
  • 另外,特別提一下,若你在 getc 或 putc 前加上 f 對結果也不會有影響,即使用fgetcfputc 效果和原程式相同。

好,再來介紹最後兩個格式化輸出和輸入的函式,fscanf()fprintf() ,在使用上和以前非檔案的輸入輸出非常相像。

fprintf()

以下示範:

#include <stdio.h>
int main()
{
FILE *fp;
int var,i;
int sum = 0;
float average;

fp = fopen("message.txt","w");
if (fp == NULL) { // 檢查檔案是否成功開啟
printf("無法開啟檔案");
return 1;
}

for ( i = 0; i < 5; i++ )
{
printf("請輸入資料 %d ==> ",i+1);
scanf("%d",&var);
sum += var;
fprintf(fp,"%d\n",var); /* 將資料寫入檔案 */
}
// 計算平均值
average = (float) sum / 5.0; // 將平均值寫入檔案,格式化為小數點後 2 位
fprintf(fp,"平均值是 %5.2f",average);
fclose(fp); // 關閉檔案,釋放系統資源
return 0;
}

程式執行後的文件內容:

88
96
46
87
100
平均值是 83.40

fscanf()

以下示範:

假設文件內容如下:

共有25個數字
65 66 67 68 69
70 71 72 73 74
75 76 77 78 79
80 81 82 83 84
85 86 87 88 89

程式碼:

#include <stdlib.h>
#include <stdio.h>
int main()
{
FILE *fp;
char line[100];
int i,j,var;

fp = fopen("message.txt","r"); /* 開啟檔案 */
fscanf(fp, "%[^\n]%*c", line); // 讀取直到換行符的內容
printf("%s\n", line); // 輸出第一行的內容
for ( i = 0; i < 5; i++ )
{
for ( j = 0; j < 5; j++ )
{
fscanf(fp,"%d",&var); // 讀取有效數字。
printf("%c",var);
}
printf("\n");
}
fclose(fp); // 關閉檔案,釋放系統資源
return 0;
}
  • %*c:讀取一個字元(通常是換行符 \n),但不存儲(* 表示忽略該輸入)。這表示讀取完一整行後直接跳至下一行。
  • 就算使用fscanf(fp, "%[^\n]", line);,輸出結果也一樣,因為fscanf(fp,"%d",&var); 自動跳過換行符,只關注數字。

程式執行後的文件內容:

共有25個數字
ABCDE
FGHIJ
KLMNO
PQRST
UVWXY

有關文件的操作目前先介紹到這邊。

留言
avatar-img
電資鼠 - 您的學習好夥伴
19會員
242內容數
在當今數位時代,電資領域人才需求爆發式成長,不論是前端網頁設計、嵌入式開發、人工智慧、物聯網還是軟硬體整合,這些技術都在改變世界。而掌握 C/C++、Python、數位邏輯、電路學與嵌入式開發等大學電資領域的課程,正是進入這個高薪、高需求產業的關鍵!
2025/03/07
本章節將探討左下三角稀疏矩陣。
Thumbnail
2025/03/07
本章節將探討左下三角稀疏矩陣。
Thumbnail
2025/03/07
相信讀者現在對於鏈結串列有了更多的認識,所以我再進一步,示範更多關於鏈結串列的操作,這部分示範會將程式模組化。將鏈結串列的操作寫進一個標頭檔,並在主程式中引入。
Thumbnail
2025/03/07
相信讀者現在對於鏈結串列有了更多的認識,所以我再進一步,示範更多關於鏈結串列的操作,這部分示範會將程式模組化。將鏈結串列的操作寫進一個標頭檔,並在主程式中引入。
Thumbnail
2025/03/07
本章節示範透過「陣列索引」和「指標運算」兩種方式來存取同一個二維陣列 a,並印出相同的數值以及對應的位址,以說明它們其實指向的是同一塊連續的記憶體空間。本文將依序解釋各段程式碼,並示範可能的執行結果與背後原理。
Thumbnail
2025/03/07
本章節示範透過「陣列索引」和「指標運算」兩種方式來存取同一個二維陣列 a,並印出相同的數值以及對應的位址,以說明它們其實指向的是同一塊連續的記憶體空間。本文將依序解釋各段程式碼,並示範可能的執行結果與背後原理。
Thumbnail
看更多
你可能也想看
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
Lua 開檔寫檔的運用 io.output()...
Thumbnail
Lua 開檔寫檔的運用 io.output()...
Thumbnail
User Input & Tables 的使用
Thumbnail
User Input & Tables 的使用
Thumbnail
工具功能 (1) 彈性任意查詢檔案,如對來源目錄設定,檔案修改日期 設定,檔名特定字串或副檔名設定後,自動查出明細,並可展開至各階子目錄處理     (2) 依查詢後結果,可產出 LIST ,提供查詢結果之確認,再依此對檔案作複 (3) 可對檔案作移動,複製至別處,刪除處理,使電腦可騰出硬碟空間
Thumbnail
工具功能 (1) 彈性任意查詢檔案,如對來源目錄設定,檔案修改日期 設定,檔名特定字串或副檔名設定後,自動查出明細,並可展開至各階子目錄處理     (2) 依查詢後結果,可產出 LIST ,提供查詢結果之確認,再依此對檔案作複 (3) 可對檔案作移動,複製至別處,刪除處理,使電腦可騰出硬碟空間
Thumbnail
C#程式由一或多個檔案組成,包含命名空間、類別、結構、介面、列舉和委派等型別。Main方法是C#應用程式的進入點。在C#中,註解用於在程式碼中添加說明,有單行和多行兩種類型。變數的定義需要指定變數的類型和名稱,可以一次為多個變數賦值。
Thumbnail
C#程式由一或多個檔案組成,包含命名空間、類別、結構、介面、列舉和委派等型別。Main方法是C#應用程式的進入點。在C#中,註解用於在程式碼中添加說明,有單行和多行兩種類型。變數的定義需要指定變數的類型和名稱,可以一次為多個變數賦值。
Thumbnail
INI 檔案是一種配置檔案格式,常用於保存設定資料和組態資訊。 它使用簡單的鍵值對結構來組織資料,通常用於程式、應用程式或操作系統中的配置和初始化設定。 INI 檔案每個鍵值對包含一個名稱(鍵)和對應的值。 基本的檔案格式如下: [Section1] Key1 = Value1 Key2 =
Thumbnail
INI 檔案是一種配置檔案格式,常用於保存設定資料和組態資訊。 它使用簡單的鍵值對結構來組織資料,通常用於程式、應用程式或操作系統中的配置和初始化設定。 INI 檔案每個鍵值對包含一個名稱(鍵)和對應的值。 基本的檔案格式如下: [Section1] Key1 = Value1 Key2 =
Thumbnail
<iostream> ​在之前的文章有提到過,<iostream> 是專門處理程式的輸入 (input) 以及輸出 (output) 的函式庫。輸入輸出的對象是以電腦作為主角: 輸入指的是「把資料給電腦」,輸出指的是「從電腦那邊取得資料」。 在這個系列的文章中,程式輸入指的都是從鍵盤輸入資料給電
Thumbnail
<iostream> ​在之前的文章有提到過,<iostream> 是專門處理程式的輸入 (input) 以及輸出 (output) 的函式庫。輸入輸出的對象是以電腦作為主角: 輸入指的是「把資料給電腦」,輸出指的是「從電腦那邊取得資料」。 在這個系列的文章中,程式輸入指的都是從鍵盤輸入資料給電
Thumbnail
關於程式語言的學習,只要掌握住幾個基本特性要熟悉幾種程式語言也不困難,這三個基本特性就是…
Thumbnail
關於程式語言的學習,只要掌握住幾個基本特性要熟悉幾種程式語言也不困難,這三個基本特性就是…
Thumbnail
介紹C++ 語法 資料型態,架構說明 程式語言為人類與電腦溝通的工具 程式設計流程: 定義問題 -> 問題分析 -> 撰寫演算法 ->程式撰寫 -> 程式執行及維護
Thumbnail
介紹C++ 語法 資料型態,架構說明 程式語言為人類與電腦溝通的工具 程式設計流程: 定義問題 -> 問題分析 -> 撰寫演算法 ->程式撰寫 -> 程式執行及維護
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News