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

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

在當今數位時代,電資領域人才需求爆發式成長,不論是前端網頁設計、嵌入式開發、人工智慧、物聯網還是軟硬體整合,這些技術都在改變世界。而掌握 C/C++、Python、數位邏輯、電路學與嵌入式開發等大學電資領域的課程,正是進入這個高薪、高需求產業的關鍵!
留言
avatar-img
留言分享你的想法!

































































C Preprocessor 負責在編譯之前對原始程式碼進行處理。其所執行的一些動作包刮了: 將其它檔案含入編譯的檔案中、定義符號常數和巨集、程式碼的條件式編譯、以及條件式執行的前置處理器命令。所有前置處理器命令都會以# 開始。本章會讓你對前置處理器有一些初步的認識與了解。
上節我們有提到過指標陣列,即陣列元素是指標,這與「指向陣列的指標」不同,千萬不要混淆。 今天這節要來講函式指標、指標型態轉換。
本篇文章深入淺出地介紹 C 語言中的資料型別,包含 enum、struct、union 和 typedef 的使用方法與應用情境。並透過圖解說明 struct 的記憶體配置和 union 的特性,以及位元組順序 (Endianness) 的概念。文末並附帶練習題,幫助讀者理解相關知識。
這篇文章深入淺出地解釋了 C 語言中指標陣列的概念,並透過範例程式碼和練習題幫助讀者理解指向指標的指標(char **)、指標陣列(char *[])等等的觀念與用法。文章還包含了指標常數(char * const)與常數指標(const char * const)的練習題,提升讀者的學習成效。
本章將介紹 C 語言的字串指標,讓讀者對於此概念有正確的理解。
本章將介紹 C 語言的字元陣列 (char array[]) 與字串函式 (string.h),這是處理 文字資料 的核心技術。C 語言以 字元陣列或指標 (char *) 來表示字串,並透過 標準函式 (strlen(), strcpy(), strcat(), strcmp()) 進行字串操作。
C Preprocessor 負責在編譯之前對原始程式碼進行處理。其所執行的一些動作包刮了: 將其它檔案含入編譯的檔案中、定義符號常數和巨集、程式碼的條件式編譯、以及條件式執行的前置處理器命令。所有前置處理器命令都會以# 開始。本章會讓你對前置處理器有一些初步的認識與了解。
上節我們有提到過指標陣列,即陣列元素是指標,這與「指向陣列的指標」不同,千萬不要混淆。 今天這節要來講函式指標、指標型態轉換。
本篇文章深入淺出地介紹 C 語言中的資料型別,包含 enum、struct、union 和 typedef 的使用方法與應用情境。並透過圖解說明 struct 的記憶體配置和 union 的特性,以及位元組順序 (Endianness) 的概念。文末並附帶練習題,幫助讀者理解相關知識。
這篇文章深入淺出地解釋了 C 語言中指標陣列的概念,並透過範例程式碼和練習題幫助讀者理解指向指標的指標(char **)、指標陣列(char *[])等等的觀念與用法。文章還包含了指標常數(char * const)與常數指標(const char * const)的練習題,提升讀者的學習成效。
本章將介紹 C 語言的字串指標,讓讀者對於此概念有正確的理解。
本章將介紹 C 語言的字元陣列 (char array[]) 與字串函式 (string.h),這是處理 文字資料 的核心技術。C 語言以 字元陣列或指標 (char *) 來表示字串,並透過 標準函式 (strlen(), strcpy(), strcat(), strcmp()) 進行字串操作。
你可能也想看
Google News 追蹤
Thumbnail
Lua 開檔寫檔的運用 io.output()...
Thumbnail
工具功能 (1) 彈性任意查詢檔案,如對來源目錄設定,檔案修改日期 設定,檔名特定字串或副檔名設定後,自動查出明細,並可展開至各階子目錄處理     (2) 依查詢後結果,可產出 LIST ,提供查詢結果之確認,再依此對檔案作複 (3) 可對檔案作移動,複製至別處,刪除處理,使電腦可騰出硬碟空間
Thumbnail
C#程式由一或多個檔案組成,包含命名空間、類別、結構、介面、列舉和委派等型別。Main方法是C#應用程式的進入點。在C#中,註解用於在程式碼中添加說明,有單行和多行兩種類型。變數的定義需要指定變數的類型和名稱,可以一次為多個變數賦值。
底下為操作流程: 打開「磁碟工具程式」 點選「檔案」 點選「新增映像檔」 點選「來自檔案夾的映像檔」 選擇要製作成「dmg」的物件 選擇要存放「dmg」的資料夾與設定(檔名、加密與映像檔格式)
Thumbnail
INI 檔案是一種配置檔案格式,常用於保存設定資料和組態資訊。 它使用簡單的鍵值對結構來組織資料,通常用於程式、應用程式或操作系統中的配置和初始化設定。 INI 檔案每個鍵值對包含一個名稱(鍵)和對應的值。 基本的檔案格式如下: [Section1] Key1 = Value1 Key2 =
Thumbnail
<iostream> ​在之前的文章有提到過,<iostream> 是專門處理程式的輸入 (input) 以及輸出 (output) 的函式庫。輸入輸出的對象是以電腦作為主角: 輸入指的是「把資料給電腦」,輸出指的是「從電腦那邊取得資料」。 在這個系列的文章中,程式輸入指的都是從鍵盤輸入資料給電
Thumbnail
關於程式語言的學習,只要掌握住幾個基本特性要熟悉幾種程式語言也不困難,這三個基本特性就是…
Thumbnail
介紹C++ 語法 資料型態,架構說明 程式語言為人類與電腦溝通的工具 程式設計流程: 定義問題 -> 問題分析 -> 撰寫演算法 ->程式撰寫 -> 程式執行及維護
Thumbnail
Lua 開檔寫檔的運用 io.output()...
Thumbnail
工具功能 (1) 彈性任意查詢檔案,如對來源目錄設定,檔案修改日期 設定,檔名特定字串或副檔名設定後,自動查出明細,並可展開至各階子目錄處理     (2) 依查詢後結果,可產出 LIST ,提供查詢結果之確認,再依此對檔案作複 (3) 可對檔案作移動,複製至別處,刪除處理,使電腦可騰出硬碟空間
Thumbnail
C#程式由一或多個檔案組成,包含命名空間、類別、結構、介面、列舉和委派等型別。Main方法是C#應用程式的進入點。在C#中,註解用於在程式碼中添加說明,有單行和多行兩種類型。變數的定義需要指定變數的類型和名稱,可以一次為多個變數賦值。
底下為操作流程: 打開「磁碟工具程式」 點選「檔案」 點選「新增映像檔」 點選「來自檔案夾的映像檔」 選擇要製作成「dmg」的物件 選擇要存放「dmg」的資料夾與設定(檔名、加密與映像檔格式)
Thumbnail
INI 檔案是一種配置檔案格式,常用於保存設定資料和組態資訊。 它使用簡單的鍵值對結構來組織資料,通常用於程式、應用程式或操作系統中的配置和初始化設定。 INI 檔案每個鍵值對包含一個名稱(鍵)和對應的值。 基本的檔案格式如下: [Section1] Key1 = Value1 Key2 =
Thumbnail
<iostream> ​在之前的文章有提到過,<iostream> 是專門處理程式的輸入 (input) 以及輸出 (output) 的函式庫。輸入輸出的對象是以電腦作為主角: 輸入指的是「把資料給電腦」,輸出指的是「從電腦那邊取得資料」。 在這個系列的文章中,程式輸入指的都是從鍵盤輸入資料給電
Thumbnail
關於程式語言的學習,只要掌握住幾個基本特性要熟悉幾種程式語言也不困難,這三個基本特性就是…
Thumbnail
介紹C++ 語法 資料型態,架構說明 程式語言為人類與電腦溝通的工具 程式設計流程: 定義問題 -> 問題分析 -> 撰寫演算法 ->程式撰寫 -> 程式執行及維護