在C語言中,我們使用FILE
指標來開啟檔案:
FILE* fptr;
現在假設我們在主程式同一目錄下有一個message.txt
文件,內容如下:
接著,我們可以使用內建fopen
函式來開啟文件。
fptr = fopen("message.txt", "r");
message.txt
文件執行不同的文件操作"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;
}
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;
}
while
迴圈以fgets()
函式做為循環的條件,該fgets()
函數逐行讀取檔案內容並將其儲存在content字串中。如果讀取成功,則條件變為真並列印。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;
}
那今天我們不想刪除原本的內容,而是想將新寫入的內容附加到原本的文件,我們改以"a"
作為函式fopen()
的第二個參數。以下示範:
#include <stdio.h>
int main() {
FILE* fp;
fp = fopen("message.txt", "a");
fputs(" so much", fp);
fclose(fp);
return 0;
}
剛才我們都是存取和程式碼同一目錄下的文件,假設你想存取外部文件的話,必須提供目錄及文件名稱,現在假設我們要存取一外部文件,而這文件位於 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()
函式,這裡我順便提一下argc
、argv*[]
如何使用,我們以一個計算字元數的程式示範如何使用,不同於以往,這次我們要在終端機編譯並執行程式:
#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!
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
,並且內容式複製過後的內容。fgetc
和fputc
效果和原程式相同。好,再來介紹最後兩個格式化輸出和輸入的函式,fscanf()
和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
有關文件的操作目前先介紹到這邊。