知識點
文件打開模式
"r"
:只讀;文件須存在。"w"
:寫入;清空或新建。"a"
:追加;文件末尾寫入。"a+"
:讀/寫追加。
追加(Append)機制
"a"
模式下,每次寫入自動定位到末尾,無須fseek(fp, 0, SEEK_END)
;安全地在不改變已有數據的前提下增加內容。
行緩沖 I/O
fgets
安全讀取帶換行的一行,防止緩沖區溢出;fputs
直接寫入字符串,不會再自動添加換行。
命令行參數處理
argc
/argv
獲取用戶輸入的文件名;fprintf(stderr, …)
打印使用說明。
錯誤處理
檢查
fopen
、fgets
、fputs
、fclose
的返回值;使用
perror
打印系統錯誤信息。
文件指針自動截斷 vs 追加
區分
"w"
(截斷)和"a"
(追加)的不同,用a
保留原有數據。
通過本練習,你將掌握文件追加模式的使用方法,以及在實際項目中如何安全、可靠地向已有文件追加新內容。
題目描述
編寫一個 C 程序,實現向一個已存在的文本文件末尾追加內容,要求:
程序從命令行接收一個文件名參數;
以追加模式打開該文件;
提示用戶輸入多行文本,以單獨一行只含
.
結束;將每行文本追加到文件末尾;
追加完畢后,重新打開文件并顯示追加后的全部內容;
全過程需對文件操作的返回值做錯誤檢查,并添加充分注釋;
在文末總結本程序涉及的知識點。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX_LEN 1024 //每行最大長度int main(int argc, char *argv[])
{if(argc != 2){fprintf(stderr,"用法:%s <已存在的文件名>\n",argv[0]);return EXIT_FAILURE;}const char *filename = argv[1];char buffer[MAX_LEN];//1.以“追加”模式打開文件//“a”只寫追加,目標自動移動到文件末尾//若需要既讀又寫可用“a”FILE *fp = fopen(filename,"a");if(!fp){perror("打開文件追加失敗");return EXIT_FAILURE;}//2.讀取用戶輸入并追加到文件末尾printf("請輸入要追加的內容(單獨一行“.”結束):\n");while (1){if(!fgets(buffer,sizeof buffer,stdin)){perror("讀取標準輸入失敗");fclose(fp);return EXIT_FAILURE;}//檢測結束標志if(strcmp(buffer,".\n") == 0 || strcmp(buffer,".") == 0){break;}//將改行寫入文件if(fputs(buffer,fp) == EOF){perror("寫入文件失敗");fclose(fp);return EXIT_FAILURE;}}//3.關閉追加if(fclose(fp) == EOF){perror("關閉追加流失敗");return EXIT_FAILURE;}//4.重新以只讀模式打開文件,顯示全部內容fp = fopen(filename,"r");if(!fp){perror("打開文件讀取失敗");return EXIT_FAILURE;}printf("\n-------------追加后的文件內容-----------------\n");while(fgets(buffer,sizeof buffer,fp)){fputs(buffer,stdout);}printf("------------------------------------------------\n");if(fclose(fp) == EOF){perror("關閉讀取流失敗");return EXIT_FAILURE;}return EXIT_SUCCESS;}
代碼講解
命令行參數
int main(int argc, char *argv[])
argc
為參數個數,argv[0]
是程序名,argv[1]
應為目標文件名。if (argc!=2)
檢查用戶是否正確提供了一個參數。
追加模式打開
FILE *fp = fopen(filename, "a");
模式
"a"
:寫操作總是從文件末尾開始,不會破壞原有內容;若文件不存在,
"a"
會創建新文件(要注意,本題要求文件已存在,可在打開后檢查文件是否為空或在打開前用access()
驗證存在性)。
讀取并追加
while (fgets(buffer, sizeof buffer, stdin)) { if (strcmp(buffer, ".\n")==0 || strcmp(buffer,".")==0) break; fputs(buffer, fp); }
fgets
從標準輸入讀取一行,保留末尾\n
;遇到單獨一行
.
立刻停止;fputs
寫入至追加流,無需再fseek
——"a"
模式自動定位末尾。
關閉流與錯誤檢查
if (fclose(fp) == EOF) perror("關閉追加流失敗");
fclose
會刷新緩沖區并釋放資源;始終檢查返回值,捕獲磁盤 I/O 錯誤。
重新打開并顯示內容
fp = fopen(filename, "r"); while (fgets(buffer, sizeof buffer, fp)) fputs(buffer, stdout);
用
"r"
模式只讀打開;再次用
fgets
/fputs
按行顯示全部文本。
char buffer[MAX_LEN];
fgets(buffer, sizeof buffer, stdin);
功能
從指定的輸入流(這里是標準輸入stdin
)讀取一行文本(或最多size–1
個字符),并把它存入buffer
。如果遇到換行符也會讀入并存儲在buffer
中,最后在末尾自動加上'\0'
。原型
char *fgets(char *s, int size, FILE *stream);
參數
char *s
—— 目標緩沖區地址,函數會把讀到的字符寫到s[0]
…int size
—— 緩沖區大小,最多讀入size-1
個字符,保證有空間存放終止符'\0'
。FILE *stream
—— 要讀取的文件流,stdin
表示標準輸入。
返回值
成功時返回
s
;遇到 EOF 或發生錯誤時返回
NULL
。
相關/替代函數
fgets(buffer, n, fp)
:從任意FILE *fp
(文件)中讀取。不要用已廢棄的
gets
(不安全,會緩沖區溢出)。如果只想讀一個字符,可用
int c = fgetc(stream);
。
fputs(buffer, fp);
功能
將以'\0'
結尾的字符串buffer
寫入到指定的輸出流fp
。不會自動添加換行符。原型
int fputs(const char *s, FILE *stream);
參數
const char *s
—— 要寫入的 C 字符串的地址。FILE *stream
—— 目標文件流,可以是任何通過fopen
打開的文件,或標準輸出stdout
、標準錯誤stderr
。
返回值
寫入成功時返回 非負值(通常是字符數或任意非
EOF
)。失敗時返回
EOF
。
相關/替代函數
puts(buffer)
:等價于fputs(buffer, stdout)
,并在末尾自動加'\n'
。fprintf(fp, "%s", buffer)
:更靈活,可混合格式化。fwrite(buffer, 1, strlen(buffer), fp)
:二進制寫入。
while (fgets(buffer, sizeof buffer, fp)) {…
}
功能
和第 1 條完全相同,只不過這里stream
不是stdin
,而是你自己打開的文件流fp
。
用它可以逐行讀取整個文件。常見用法
FILE *fp = fopen("file.txt", "r"); while (fgets(buffer, sizeof buffer, fp)) {// buffer 中包含一整行文本(包括換行符)process(buffer);//偽代碼/示例里的占位符,意思是對剛讀入的這一行文本做一些處理 } fclose(fp);
其他輸入流
fgets(buffer, size, stdin)
:從鍵盤讀行fgets(buffer, size, pipe_fp)
:從管道讀行fgets(buffer, size, socket_fp)
(如果你把 socket 包裝成 FILE*)
fputs(buffer, stdout);
功能
把字符串寫到標準輸出。等同于printf("%s", buffer)
,但比printf
略高效,因為無需解析格式串。常見用法
puts(buffer); // 自動加 '\n'
fputs(buffer, stdout); // 不加 '\n'
相關輸出流
fputs(buffer, stderr)
:輸出到標準錯誤,一般用于打印錯誤或日志。fputs(buffer, fp)
:輸出到用戶打開的任意文件流。
小結
fgets
:按行(或按長度)從一個FILE *
讀字符串,保留'\n'
并自動加'\0'
。fputs
:把一個 C 字符串寫入一個FILE *
,不附加'\n'
。常見流:
輸入:
stdin
、文件流fp
;輸出:
stdout
、stderr
、文件流fp
。
替代函數:
輸入:
fgetc
、getc
、gets
(已廢棄)、getline
(POSIX 擴展);輸出:
puts
、printf
、fprintf
、fwrite
。
掌握這些函數及其參數后,你就能靈活地在控制臺、文件或其他 I/O 流之間進行文本讀寫了。