当前位置: 首页 > news >正文

C语言--文件读写函数的使用

目录

一、前言

  1. 文件访问模式
  2. 流和标准流

二、顺序读写函数的介绍: fgetc、 fputc、 fgets、fputs、 fscanf、 fprintf、fread、 fwrite

三、应用:把一个文件的数据拷贝到另一个文件上

四、文件读取结束的判定

  1. 被错误使用的 feof
  2. 使用方法

五、总结

前言

文件访问模式

使用fopen来打开文件,就要了解关于文件的访问模式:
在这里插入图片描述
在这里插入图片描述

注意:
使用“r”打开文件,打开的文件必须存在,否则,程序出错
使用“w”打开文件,如果文件存在,并且文件中有数据,会清空数据。文件不存在,会建一个新文件

打开文件用fopen

FILE * fopen ( const char * filename, const char * mode );

有文件的打开就有文件的关闭,
关闭文件用fclose

int fclose ( FILE * stream );

具体操如下:

int main()
{FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return;}//写文件//关闭文件fclose(pf);pf = NULL;return 0;
}

流和标准流

在学习读写函数前,先要了解流和标准流的概念

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流想象成流淌着字符的河。
C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。
⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。

标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?
那是因为C语⾔程序在启动的时候,默认打开了3个流:
• stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。
• stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出
流中。
• stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。
这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。
stdin、stdout、stderr 三个流的类型是: FILE* ,通常称为⽂件指针。
C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。

fputc

字符输出到流上

int fputc ( int character, FILE * stream );

参数类型

第一个参数:要输出的字符
第二个参数:流

使用方法

可以一个一个字符写,也可以使用循环

int main()
{FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen fail");return;}//写文件/*fputc('a', pf);fputc('b', pf);fputc('c', pf);*/char ch = 0;for (ch = 'a'; ch <= 'z'; ch++){fputc(ch, pf);}//关闭文件fclose(pf);pf = NULL;return 0;
}

fgetc

从流中读取字符

int fgetc ( FILE * stream );

参数类型

返回值

成功读取返回读取到的字符;否则,返回EOF

使用方法

如果打开失败进入if语句;perror用来显示 报错信息

int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen fail");return;}//读文件int ch = 0;while ((ch=fgetc(pf))!=EOF){printf("%c", ch);}//关闭文件fclose(pf);pf = NULL;return 0;
}

fputs

把字符串输出到流上

int fputs ( const char * str, FILE * stream );

参数类型

str:存储字符串的数组指针
stream:流

使用方法

int main()
{//打开文件FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return;}//写文件fputs("hello world\n", pf);fputs("hello bit\n", pf);//关闭文件fclose(pf);pf = NULL;return 0;
}

fgets

从流中读取字符并将它们作为字符串存储到 str 中

char * fgets ( char * str, int num, FILE * stream );

参数类型

str:存储读取到的字符串,的数组指针
num:读取字符数
stream:流

返回值

读取成功,返回读取到的字符串。
否则,返回NULL

使用方法

注意:
fgets只读一行 实际读取num-1个字符,末尾要加\0
如果有多行数据 第一行的字符数不够 读完字符 长度允许再加\n, 末尾再补\0
就是会把\n(换行符)读进去

int main()
{//打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return;}//读文件char arr[20] = { "0"};while (fgets(arr, 20, pf) != NULL){printf("%s", arr);}//fgets(arr, 20, pf);//只读一行 第一行的字符数够  实际只读9个字符,末尾要加\0//printf("%s", arr);//第一行的字符数不够 读完字符 长度允许再加\n, 末尾再补\0 //关闭文件fclose(pf);pf = NULL;return 0;
}

fprintf

把格式化的数据打印在指定输出流上
会使用 printf就会使用 fprintf,我们来比对这两个函数
发现 fprintf就比 printf多了一个参数 stream:文件流

int printf ( const char * format, ... );
int fprintf ( FILE * stream, const char * format, ... );

参数类型

比printf多了一个参数 stream:流

使用方法

和printf的使用方法一样

struct S
{char name[20];int age;float score;
};
int main()
{struct S s = { "张三",20,65.5f };//想把s中的数据存放在文件中FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return;}//写文件fprintf(pf,"%s %d %f", s.name, s.age, s.score);fclose(pf);pf = NULL;return 0;
}

fscanf

在指定输入流上读取格式化数据

int scanf ( const char * format, ... );
int fscanf ( FILE * stream, const char * format, ... );

参数类型

会使用scanf就会使用fscanf,我们来比对这两个函数
发现fscanf就比scanf多了一个参数 stream:文件流

返回值

成功读取:返回成功填充的参数列表的项数
否则,返回EOF

使用方法

fscanf和scanf的使用方法一样

struct S
{char name[20];int age;float score;
};
int main()
{struct S s = { 0 };//想从文件test.txt中读取数据放到s中FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return;}//读文件fscanf(pf, "%s %d %f", s.name, &s.age, &s.score);//printf("%s %d %f", s.name, s.age, s.score);fprintf(stdout,"%s %d %f", s.name, s.age, s.score);fclose(pf);pf = NULL;return 0;
}

应用

把data.txt 文件的数据拷贝到data_copy.txt文件上

int main()
{FILE* pr = fopen("data.txt", "r");if (pr == NULL){perror("fopen");return;}FILE* pw = fopen("data_copy.txt", "w");if (pw == NULL){perror("fopen");fclose(pw);return;}//读/写文件int ch = 0;while ((ch=fgetc(pr)) != EOF){fputc(ch, pw);}//char ch[20] = { 0 };//while (fgets(ch, 20, pr) != NULL)//{//	fputs(ch, pw);//}/*char ch[200] = { 0 };while (fscanf(pr, "%s", ch) != EOF){fprintf(pw, "%s ", ch);}*///关闭文件fclose(pw);pw = NULL;fclose(pr);pr = NULL;return 0;
}

fwrite

以二进制的形式写到流上

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

参数类型

ptr:指向要写入的元素数组的指针
size:要写入的每个元素的大小
count:元素个数
stream:流

使用方法

fwrite 以二进制的形式写进去 从数组里写count个size大小的数据到文件里

int main()
{int arr[] = { 1,2,3,4,5 };FILE* pf = fopen("test.txt", "wb");if (pf == NULL){perror("fopen");return;}//写数据int sz = sizeof(arr) / sizeof(arr[0]);fwrite(arr, sizeof(arr[0]), sz, pf);//以二进制的形式写进去的fclose(pf);pf = NULL;return 0;
}

fread

从流上以二进制的形式读出来

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

参数类型

ptr:指向大小至少为 (size*count) 字节的内存块的指针
size:要写入的每个元素的大小
count:元素个数
stream:流

使用方法

fread 以二进制的形式读出来 从文件里读count个size大小的数据到数组里

int main()
{int arr[5] = { 0 };FILE* pf = fopen("test.txt", "rb");if (pf == NULL){perror("fopen");return;}//读数据int i = 0;while (fread(&arr[i], sizeof(int), 1, pf))//fread 返回值:成功读取到的总元素个数{i++;printf("%d ", arr[i]);}//fread(arr, sizeof(arr[0]), 5, pf);//for (int i = 0; i < 5; i++)//{//	printf("%d ", arr[i]);//1 2 3 4 5//}fclose(pf);pf = NULL;return 0;
}

文件读取结束的判定

使用 feof 和 ferror来判断文件读取结束的原因

被错误使用的 feof

牢记:在文件读取过程中,不能用feof函数的返回值直接来判断文件的是否结束。
feof 的作用是:当文件读取结束的时候,判断读取结束的原因是否是:遇到文件尾结束。

  1. ⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
    例如:
    • fgetc 判断是否为 EOF .
    • fgets 判断返回值是否为 NULL .
  2. ⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数。

使用方法

⽂件读取结束的判定
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return;}//读取int ch = 0;while ((ch = fgetc(pf)) != EOF){printf("%c\n", ch);}//判断是什么原因导致⽂件读取结束if (feof(pf))//feof 遇到⽂件尾结束 返回一个非零值,否则 返回0{printf("遇到文件末尾,读取正常结束\n");}else if (ferror(pf))//ferror 遇到错误结束 返回非零值,否则 返回0{perror("fgetc");}fclose(pf);pf = NULL;return 0;
}

总结

这里只介绍了顺序读写函数,还有随机读写函数 fseek,ftell,rwind,感兴趣的小伙伴可以自己了解。这次的分享就到这,如果对你有帮助,请给博主点点关注,如果你有任何疑问或想要深入探讨的话题,也欢迎在评论区留言,我们一起来探讨。

http://www.dtcms.com/a/588884.html

相关文章:

  • 网站的网站维护的原因可以做公众号的网站
  • 使用waitpid回收多个子进程
  • leetcode1547.切棍子的最小成本
  • ThinkPHP8学习篇(十一):模型关联(一)
  • 深入理解Ribbon的架构原理
  • 力扣(LeetCode)100题:3.无重复字符的最长子串
  • 前端接口安全与性能优化实战
  • ssh网站怎么做wordpress搬家_后台错乱
  • LangChain V1.0 Messages 详细指南
  • 网站商城微信支付接口申请软件开发人工收费标准
  • 代码生成与开发辅助
  • claude code访问本地部署的MCP服务
  • 学习笔记8
  • Vue编程式路由导航
  • android contentprovider及其查看
  • 根据网站做软件免费网站app下载
  • Rust 练习册 :解开两桶谜题的奥秘
  • 2025.11.03作业 WEB服务
  • Electron 应用中的系统检测方案对比
  • 秦皇岛 网站制作怎么做网站推广临沂
  • oj 数码积和(略难
  • RT-Thread开发实战 --- PIN设备的使用
  • Android的binder机制理解
  • 二十五、STM32的DMA(数据转运)
  • 湖北省建设厅政务公开网站wordpress加速网站插件
  • 提示词(Prompt)工程与推理优化
  • 简析单目相机模型中的针孔模型
  • Apache Flink CDC——变更数据捕获
  • 从“数据堆场”到“智能底座”:TDengine IDMP如何统一数据语言
  • 从细胞工厂到智能制造:Extracellular 用 TDengine 打通数据生命线