文件操作知识系统整理
一、文件基础概念
-
文件分类
分类维度 具体类型 说明 逻辑结构 文本文件、二进制文件 数据存储形式 存储介质 磁盘文件、光盘文件、内存文件 物理存储载体 数据组成形式 顺序文件、索引文件、链式文件 数据组织方式 -
文件名组成
[文件路径] + [文件名主干] + [文件后缀] 示例:C:\data\example.txt - 路径:C:\data\ 主干:example 后缀:.txt
二、文件系统与操作
-
文件指针与操作流程
FILE *pf; // 指向文件信息区的指针 pf = fopen("filename", "mode"); // 打开文件 if (pf == NULL) { perror("Error"); // 错误处理 return 1; } // 文件读写操作... fclose(pf); // 关闭文件(成功返回0,失败返回EOF) pf = NULL; // 避免野指针文件打开模式 (
mode参数)模式 功能 r只读,文件必须存在 w只写,创建新文件或清空现有文件 a追加,写入数据到文件末尾 rb二进制读模式 -
路径类型
类型 示例 说明 绝对路径 C:\data\file.txt完整路径,从根目录开始 相对路径 ../src/main.c相对于当前工作目录
三、文件读写操作
-
字符级读写
// 字符写入 fputc('A', pf); // 成功返回写入字符,失败返回EOF // 字符读取 int ch = fgetc(pf); // 使用int接收(兼容EOF=-1) -
行级读写
// 读取一行 char buffer[100]; fgets(buffer, 100, pf); // 写入一行 fputs("Hello World", pf); -
二进制读写
// 写入结构体 struct Student stu = { "Alice", 20 }; fwrite(&stu, sizeof(struct Student), 1, pf); // 读取结构体 fread(&stu, sizeof(struct Student), 1, pf);
四、示例
1.带命令行参数的main函数
int main(int argc, char *argv[]) {
// 代码逻辑
return 0;
}
-
参数说明:
argc:命令行参数个数(包括程序自身名称)。argv:字符串指针数组,存储命令行参数的具体内容。argv[0]:程序名称。argv[1]到argv[argc-1]:用户输入的参数。
1)处理命令行参数
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("程序名称: %s\n", argv[0]);
printf("参数个数: %d\n", argc - 1);
for (int i = 1; i < argc; i++) {
printf("参数 %d: %s\n", i, argv[i]);
}
return 0;
}
运行效果
$ ./program apple banana
程序名称: ./program
参数个数: 2
参数 1: apple
参数 2: banana
2)打印出命令行中传递给程序的所有参数
int main(int argc, char **argv)
{
int i;
for(i=0; i<argc; i++)
printf("%s\n", argv[i]);
return 0; // 通常返回0表示程序成功执行
}
-
函数定义:
int main(int argc, char **argv)main是C程序的入口点,程序从这里开始执行。argc(Argument Count)是一个整数,表示命令行参数的数量。argv(Argument Vector)是一个指向字符串数组的指针,每个字符串代表一个命令行参数。
变量声明:
int i;声明一个整型变量
i,用于循环计数。- 循环遍历参数:
for(i=0; i<argc; i++) printf("%s\n", argv[i]); -
for循环从0开始,依次访问每个参数,直到i等于argc(此时已遍历完所有参数)。 -
argv[0]通常是程序本身的名称(例如./a.out)。 -
argv[1]到argv[argc-1]是用户在命令行中提供的实际参数。 -
printf("%s\n", argv[i])会打印每个参数字符串,并在末尾添加换行符\n。
示例:
如果在命令行中执行:
./program(你的文件名) hello world 123
程序会输出:
./program
hello
world
123
以空格为分隔符,例如hello是一个字符串
3)C程序默认打开的流
2.实现cat(显示到屏幕上)功能
将指定文件的内容逐字符读取并输出到标准输出(通常是终端)。
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "用法:%s <文件名>\n", argv[0]);
return 1;
}
FILE *pf = fopen(argv[1], "r");
if (pf == NULL) {
perror("无法打开文件");
return 1;
}
int ch;
while ((ch = fgetc(pf)) != EOF) {
fputc(ch, stdout);
}
fclose(pf); // 关闭文件
return 0;
}
1) 函数定义与参数
int main(int argc, char *argv[])
main是程序的入口点。argc(Argument Count):命令行参数的数量(至少为1,即程序名本身)。argv(Argument Vector):字符串数组,存储命令行参数。argv[0]:程序名(如./program)。argv[1]:第一个参数,这里用作要读取的文件名。
2)文件操作
FILE* pf = fopen(argv[1], "r");
fopen函数尝试以只读模式("r")打开用户指定的文件(argv[1])。- 如果文件不存在或无法打开。
FILE*是指向文件流的指针,用于后续操作。
3) 字符读取与输出循环
int ch = fgetc(pf);
while (ch != EOF)
{
fputc(ch, stdout);
ch = fgetc(pf);
}
fgetc(pf):从文件流pf中读取一个字符,并返回其 ASCII 值(类型为int)。若到达文件末尾(End of File),返回EOF(通常为-1)。ch != EOF:循环条件,确保未到达文件末尾。fputc(ch, stdout):将字符ch输出到标准输出流(即屏幕)。stdout是预定义的标准输出流(类似printf的默认输出)。
- 循环逻辑:
在 C 语言中,文件流(FILE*)维护了一个内部位置指针,用于记录当前读取或写入的位置。当你调用fgetc()函数时,它会执行以下操作:- 读取当前位置的字符:从文件的当前位置读取一个字节(字符)。
- 移动位置指针:自动将文件位置指针向后移动1 个字符(即指向下一个字符)。
- 返回字符值:返回读取的字符(转换为 int 类型)。
4)字符类型问题
ch 必须是 int 类型,而非 char,以正确处理 EOF(char 无法存储 -1)。
示例运行
若编译后程序名为 copy,执行:
./copy example.txt
程序会将 example.txt 的内容逐字符复制到终端显示。
3.实现copy命令的C代码
int main(int argc, char *argv[])
{
int i;
if(argc<3) // 检查命令行参数是否足够(程序名+源文件+目标文件)
{
printf("error!Need 3 arguments!"); // 提示需要3个参数
return 0; // 参数不足时退出程序
}
FILE* fp=fopen(argv[1],"r"); // 打开第一个参数指定的文件(源文件)用于读取
FILE* fp2=fopen(argv[2],"w"); // 打开第二个参数指定的文件(目标文件)用于写入
if(fp==NULL||fp2==NULL) // 检查文件是否成功打开
{
printf("open or creat a file error!"); // 提示文件打开或创建失败
return 0; // 文件打开失败时退出程序
}
int ch=fgetc(fp); // 从源文件读取第一个字符
while(ch!=EOF) // 循环直到文件结束(EOF)
{
fputc(ch,fp2); // 将字符写入目标文件
ch=fgetc(fp); // 从源文件读取下一个字符
}
fclose(fp); // 关闭源文件
fclose(fp2); // 关闭目标文件
fp=NULL; // 避免悬空指针
return 0; // 程序正常结束
}
4.用fgets和fputs写cat命令
void myCat(char *source)
{
FILE* fp=fopen(source,"r"); // 打开源文件用于读取
if(fp==NULL)
{
perror("无法打开文件");
return ;
}
char str[200]; // 定义缓冲区存储每行内容
fgets(str,200,fp); // 读取第一行
while(!feof(fp)) // 循环直到文件结束
{
fputs(str,stdout); // 输出当前行到标准输出
fgets(str,200,fp); // 读取下一行
}
fclose(fp); // 关闭文件流
fp=NULL;
}
!feof(fp) 是C语言中用于判断文件是否结束的条件表达式,其含义为:“文件尚未结束”。下面详细解释其工作原理和潜在问题:
1) feof() 函数的作用
- 功能:
feof(FILE* stream)检查文件流是否已到达文件末尾(End of File,简称EOF)。 - 返回值:
- 若文件流已到达EOF,返回
非零值(通常为1)。 - 若文件流未到达EOF,返回
0。
- 若文件流已到达EOF,返回
2) !feof(fp) 的逻辑
!是逻辑非运算符,将feof(fp)的结果取反:- 当文件未结束时,
feof(fp)返回0,!feof(fp)为1(真),循环继续。 - 当文件结束时,
feof(fp)返回1,!feof(fp)为0(假),循环终止。
- 当文件未结束时,
3)常见误区与问题
误区示例:
while (!feof(fp)) {
fgets(str, 200, fp); // 先读取,再判断
fputs(str, stdout); // 若读取失败,str可能是上次的内容
}
问题分析:
-
最后一行重复输出:
若文件最后一行没有换行符,fgets()会读取该行并将文件指针移至EOF,但此时!feof(fp)仍为真,导致再次进入循环。此时fgets()读取失败(返回NULL),但str保留上次内容,造成重复输出。 -
安全风险:
若fgets()读取失败(如文件损坏),str内容未被更新,可能输出脏数据。
4) 推荐的循环写法
按字符读取:
int ch;
while ((ch = fgetc(fp)) != EOF) { // 读取并判断
fputc(ch, stdout);
}
按行读取:
char str[200];
while (fgets(str, 200, fp) != NULL)
{ // 读取成功时循环
fputs(str, stdout);
}

被折叠的 条评论
为什么被折叠?



