知识点
-
文件打开模式
-
"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 程序,实现向一个已存在的文本文件末尾追加内容,要求:
-
程序从命令行接收一个文件名参数;
-
以追加模式打开该文件;
-
提示用户输入多行文本,以单独一行只含
.结束; -
将每行文本追加到文件末尾;
-
追加完毕后,重新打开文件并显示追加后的全部内容;
-
全过程需对文件操作的返回值做错误检查,并添加充分注释;
-
在文末总结本程序涉及的知识点。
cpp
#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按行显示全部文本。
-
cpp
char buffer[MAX_LEN];
fgets(buffer, sizeof buffer, stdin);
-
功能
从指定的输入流(这里是标准输入
stdin)读取一行文本 (或最多size--1个字符),并把它存入buffer。如果遇到换行符也会读入并存储在buffer中,最后在末尾自动加上'\0'。 -
原型
cpp
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);。
-
cpp
fputs(buffer, fp);
-
功能
将以
'\0'结尾的字符串buffer写入到指定的输出流fp。不会自动添加换行符。 -
原型
cpp
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):二进制写入。
-
cpp
while (fgets(buffer, sizeof buffer, fp)) {
...
}
-
功能
和第 1 条完全相同,只不过这里
stream不是stdin,而是你自己打开的文件流fp。用它可以逐行读取整个文件。
-
常见用法
cpp
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*)
cpp
fputs(buffer, stdout);
-
功能
把字符串写到标准输出 。等同于
printf("%s", buffer),但比printf略高效,因为无需解析格式串。 -
常见用法
cpp
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 流之间进行文本读写了。