在 C 語言中,文件的讀寫是一個非常常見的需求。fopen 是標準庫中提供的函數,用來打開文件,返回一個文件指針供后續操作使用。本篇博客將詳細介紹 fopen 的使用方法、每個參數的含義,以及它與 Shell 中 >、>> 重定向符的聯系與區別。
一、fopen 函數原型
FILE *fopen(const char *filename, const char *mode);
- filename:要打開的文件路徑,可以是相對路徑或絕對路徑。
- mode:打開文件的方式,也叫“模式”,是一個字符串,控制你要如何訪問文件(讀、寫、追加等)。
返回值是一個 FILE * 類型的文件指針,如果打開失敗則返回 NULL。
二、mode 模式參數詳解
模式 | 描述 | 文件是否需要存在? | 是否會清空原文件? |
---|---|---|---|
"r" | 只讀模式打開文本文件 | 是 | 否 |
"w" | 只寫模式打開文本文件 | 否 | 是(若存在則清空) |
"a" | 追加寫入模式打開文本文件 | 否 | 否(寫入時追加) |
"r+" | 讀寫模式打開文本文件 | 是 | 否 |
"w+" | 讀寫模式,若文件存在則清空 | 否 | 是 |
"a+" | 讀寫模式,從文件末尾追加寫入 | 否 | 否 |
"rb" | 以二進制只讀方式打開文件 | 是 | 否 |
"wb" | 以二進制只寫方式打開文件 | 否 | 是 |
"ab" | 以二進制追加方式打開文件 | 否 | 否 |
2.1 “r”:只讀模式
只能讀取已有文件,文件必須存在。
#include <stdio.h>int main() {FILE *fp = fopen("data.txt", "r");if (!fp) {perror("無法打開文件");return 1;}char buffer[100];while (fgets(buffer, sizeof(buffer), fp)) {printf("%s", buffer);}fclose(fp);return 0;
}
在終端將顯示data.txt中原有的文件內容
2.2 “w” 只寫模式
fopen(“log.txt”, “w”) 以“寫模式”(“w”)打開 log.txt 文件。如果文件不存在,它會被創建。如果文件已經存在,文件的原始內容會被清空,重新寫入新內容。
fprintf(fp, “Hello, world!\n”); 這一行會將字符串 “Hello, world!\n” 寫入 log.txt 文件中。
執行完后,文件會關閉,原文件中的所有內容(包括原先的 “hello”)都會被新內容覆蓋。
假設log.txt中的內容為:
hello
那么執行下面的代碼之后:
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "w");if (!fp) {perror("無法打開文件");return 1;}fprintf(fp, "Hello, world!\n");fclose(fp);return 0;
}
因此,假設文件 log.txt 在之前包含 “hello”,再次運行此程序后,文件的內容會被重寫為:
Hello, world!
2.3 “a”:追加模式
fopen(“log.txt”, “a”) 以“追加模式”(“a”)打開文件。如果 log.txt 文件不存在,它會被創建。如果文件已經存在,新寫入的內容會被添加到文件的末尾,而不會覆蓋原有的內容。
fprintf(fp, “程序執行了一次。\n”); 這一行會把字符串 “程序執行了一次。\n” 寫入文件。
執行完后,文件會關閉。
假設文件 log.txt 中原本的內容為:
hello
那么執行下面的代碼之后:
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "a");if (!fp) {perror("無法打開文件");return 1;}fprintf(fp, "程序執行了一次。\n");fclose(fp);return 0;
}
每次執行該程序時,程序都會在文件末尾追加一行 “程序執行了一次。\n”,所以第一次執行后的文件內容會變為:
hello
程序執行了一次。
如果再次運行該程序,文件內容會變為:
hello
程序執行了一次。
程序執行了一次。
每次執行程序,都會在文件末尾追加 “程序執行了一次。\n” 這一行,而不會覆蓋原有的內容。
2.4 “r+”:讀寫模式
fopen(“log.txt”, “r+”) 以“讀寫模式”(“r+”)打開文件。這種模式要求文件必須已經存在。如果文件不存在,程序會輸出 無法打開文件 并退出。
fprintf(fp, “MODIFIED”); 會將字符串 “MODIFIED” 寫入文件,從文件的開頭開始覆蓋原有的內容。由于 “MODIFIED” 的長度是 8 個字符,它會覆蓋文件中的前 8 個字節。
假設原文件log.txt 的內容是:
hello
執行下面代碼:
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "r+");if (!fp) {perror("無法打開文件");return 1;}// 覆蓋文件前幾個字節fprintf(fp, "MODIFIED");fclose(fp);return 0;
}
執行 fprintf(fp, “MODIFIED”);,文件的前 8 個字節會被 “MODIFIED” 替換。由于 “MODIFIED” 比原來的 hello 長,因此文件會變成:
MODIFIED
2.5. “w+”:讀寫模式
fopen(“log.txt”, “w+”) 以“讀寫模式”(“w+”)打開文件。如果文件不存在,它會被創建。如果文件已經存在,它會被清空(即文件內容會被刪除),然后可以進行讀寫操作。
fprintf(fp, “Writing then reading.\n”); 這一行將字符串 “Writing then reading.\n” 寫入 log.txt 文件。
rewind(fp); 將文件指針移動回文件的開頭,為后續的讀取操作做準備。
fgets(buffer, sizeof(buffer), fp); 讀取文件內容并將其存儲在 buffer 數組中,直到遇到換行符或文件末尾。這里會讀取寫入的內容 “Writing then reading.\n”。
printf(“讀取內容: %s”, buffer); 打印讀取到的內容。
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "w+");if (!fp) {perror("無法打開文件");return 1;}fprintf(fp, "Writing then reading.\n");rewind(fp); // 返回文件開頭char buffer[100];fgets(buffer, sizeof(buffer), fp);printf("讀取內容: %s", buffer);fclose(fp);return 0;
}
控制臺會輸出:
讀取內容: Writing then reading.
文件 log.txt 的內容會變為:
Writing then reading.
2.6 “a+”:讀寫追加模式
log.txt 文件的內容將被 追加 新數據,同時程序會讀取并打印文件的全部內容。
fopen(“log.txt”, “a+”);
- 打開文件 log.txt,模式為 “a+”,表示 讀寫追加模式。
- 如果文件不存在,它會被創建;如果文件存在,原有內容 不會被清空,且新的寫入內容會追加到文件末尾。
- 該模式允許讀取和寫入操作,但是寫入內容總是從文件末尾開始,不會覆蓋原有數據。
fprintf(fp, “添加一行數據\n”);
- 向文件追加一行數據 “添加一行數據\n”。由于是 “a+” 模式,文件指針會自動移到文件末尾,新的內容會添加到文件的末尾。
rewind(fp);
- 將文件指針重置到文件開頭。這樣做的目的是為了能夠從文件的開始位置讀取內容。
while (fgets(buffer, sizeof(buffer), fp))
- 使用 fgets 逐行讀取文件內容,并將讀取的每行內容打印出來。由于文件指針已被 rewind()
移動到文件開頭,這個循環將從文件的第一行開始讀取并輸出。
假設文件 log.txt 原始內容是:
hello
執行下面代碼后:
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "a+");if (!fp) {perror("無法打開文件");return 1;}fprintf(fp, "添加一行數據\n");rewind(fp); // 讀取需要重置到文件開頭char buffer[100];while (fgets(buffer, sizeof(buffer), fp)) {printf("%s", buffer);}fclose(fp);return 0;
}
文件內容變為:
hello
添加一行數據
程序會打印:
hello
添加一行數據
三、fopen 與 Shell 重定向 >、>> 的關系與區別
Shell 中的重定向:
1.>:輸出重定向,若文件存在則清空,等價于 fopen(“file.txt”, “w”)。
2.>>:追加輸出,文件存在時追加到末尾,等價于 fopen(“file.txt”, “a”)。
對比總結:
操作 | Shell 表達方式 | C 語言等價 fopen 模式 |
---|---|---|
重定向輸出到文件(覆蓋) | command > file.txt | "w" |
追加輸出到文件 | command >> file.txt | "a" |
示例:
echo "日志內容" > log.txt # 覆蓋寫入
echo "更多日志" >> log.txt # 追加寫入