C语言笔记:文件的操作各种文件函数讲解

突然发现自己的C语言文件部分还没有学,赶紧来补一下~~

1.文件分类

  • 文本文件
  • 磁盘文件(二进制文件)
  • C语言特殊文件标识:stdin(标准输入:通指键盘输入),stdout(标准输出:通指屏幕输出),自定义文件(FILE)

2.文件操作

打开文件与关闭文件:fopen&fclose

打开文件使用的是函数:FILE*fopen(char*strURL,char*mode);第一个参数是文件的路径,第二是读写方式,二者都是以字符串形式存在的。

关闭文件使用的是:int fclose(FILE*strurl);注意,不能关闭空文件!!

下面来介绍一下读写方式的分类以及他们的功能:(注意,写在函数里的时候,虽然是一个字母,但是也要加上双引号代表字符串的地址哦

读写方式作用
r:read

读的方式打开文件,相当于是一种只读模式,

如果文件不存在函数返回空

w:write

写的方式打开文件,如果文件不存在,那么创建一个文件;

如果文件存在,那么会将源文件清空。

a:append追加写的方式打开文件,即我们不会清除原文件,而是会原来文件的后面接着写;如果文件不存在,那么返回空。
组合方式:w+,r+,a++代表可读可写,加上之后都变成可读可写了,只不过返回的时候有区别
rb,wb,abb代表以二进制的方式进行读写。我们还可以再加上+,和上面的意思一样

下面上一段代码看看具体的操作

FILE*fp=fopen("firstfile.file","w");
fclose(fp);

很神奇的一点在于,你可以在这个fopen函数里面创建任意类型的文件,文件后缀其实没有什么太大关系。比如上面创建一个file类型的文件,并在里面进行写的操作。

我们还需要关心的是,如果这个文件是我们创建的,那么他的具体位置在哪里呢?我们来看下图:

从上面我们可以看出,假如你要打开的文件是之前没有的,那么电脑会把它创建在和原来的c源文件的exe执行文件在一个文件夹里面。string是我这个新文件进行操作的c源文件。

如果我们写了一个新的文件类型,可能计算机无法识别,我在这里选用记事本打开然后进行写入。

 然后我们返回看一下文件改变了没有。

很明显文件大小变了,说明写入成功!

字符读写:fgetc与fputc

这两个是以字符形式读取文件和写文件。读取时,fgetc接受文件指针,然后每次读一个字符,然后文件指针会自动进行移动,每次进行下一步操作的时候,他就会读取后面的字符。每个文件的结尾都会有一个结束标识符叫做EOF,当读取到EOF的时候就会停止。

先来看fgetc函数

 FILE*fp=fopen("firstfile.file","r");
   int ch=fgetc(fp);
while(ch!=EOF){
printf("%c",ch);
ch=fgetc(fp);
}
fclose(fp);

注意点:由于每次调用fgetc函数的时候都会把指针向前进行移动,因此我们必须用另外一个变量来存储得到的结果,否则就会出现有一些字符被跳过的情况。(和指针的++操作类似)

 再来看fputc函数,很明显,他需要有两个参数,一个是需要传进去的参数字符c,另外就是需要穿进去的文件名称。

我们尝试用追加的方式在上面的文件中写入一个字符串。

FILE*newfile=fopen("first.file","a");
char str[]={"chicken is beautiful!!"};
int i=0;
while(str[i]!='\0'){
fputc(str[i],newfile);
i++;
}
fclose(newfile);

结果如下:

字符串读写:fgets和fputs

这两个函数是读入字符串的,每次读入一行字符串或者添加一行字符串。

fgets函数是这样的,有三个参数,第一个是要存放字符串的数组的首地址,第二个是从文件流中读入的字符个数,第三个是文件的指针。

fgets函数在读取的时候,会把回车符也进行读取,因此缓冲区不会有回车符了。在使用stdin的时候,输出字符串的时候就不需要加上\n了。

 我们先使用这个函数把一系列的字符串读进一个二维数组里面,看看输出的效果如何。

FILE*readbystr=fopen("firstfile.file","r");
char*newstrs[10];
int i=0;
while(!feof(readbystr)){   //feof函数是检查文件指针是否到达了末尾
fgets(*(newstrs+i),10,readbystr);  //10代表的是每行字符最大读取10个字符
puts(*(newstrs+i));
i++;
}

fclose(readbystr);

这里我们注意到,输出的时候还多输出了一个换行符(中间空白处),我再修改文件的时候,每一行的确是输入了一个换行符。这是puts函数自己会换行决定的结果,相当于换了两次行。

当然解决的方法第一个是使用printf函数,因为他不会自己换行,%s后面不加\n即可。

第二个是自己检查有没有\n。 我是用的是strcspn函数,这个函数是查找一个字符串的首字母在另个字符串中出现的首位置。strcspn(char*str1,char*str2)str2是那个首字母的字符串,str1是被查找的字符串。返回的是被查到的字符的前面的子串的长度。比如第一个字符串为qwertyu,第二个字符串为wer,那么他会返回1,因为w的前面有一个字符,长度为1。所以我们可以这样操作,查找‘\n’的位置并把它替换成为‘\0’,这样就不会换两次行了。

while(!feof(readbystr)){
fgets(*(newstrs+i),10,readbystr);
newstrs[i][strcspn(newstrs[i],"\n")]='\0';//查找位置并进行替换操作
puts(*(newstrs+i));
i++;
}

 fputs函数相当于就是把一行字符串打印到文件中。比较简单。

FILE*newfile=fopen("firstfile.file","a");
fputs("cxk wo ai ni\n",newfile);
fputs("kunkun!!!~~~",newfile);
fclose(newfile);

提醒大家一下,记得要用“a”,不能用“r”,但凡涉及到要对文件进行修改都要用a或者w。

格式化读写:fprintf,fscanf

 fprintf相比于printf,就是多了一个打印的文件位置而已,printf打印到stdout(屏幕);同样,对fscanf,使用stdin(控制台)输入,和scanf的效果是一样的。

int num;
fscanf(stdin,"%d",&num);
fprintf(stdout,"%d\n",num);

前面第一个参数是文件的路径,后面和printf,scanf一样。

我们可以使用这两个函数对结构体进行数据输入和输出,并把他们保存到一个文件里面。这个可能会在写管理系统的时候用到。这里我写了两个函数来进行输入数据和输出数据到文件中,来看代码。

typedef  struct student
{
    char name[10];
    int age;
    int score;
}student;//这是一个学生成绩姓名年龄的结构体

void InputDataToFile(student array[],const char*filename,int arraynum){
int i=0;
FILE* fp=fopen(filename,"w");
for ( i = 0; i < arraynum; i++)
{
  fprintf(fp,"%s %d %d\n",array[i].name,array[i].age,array[i].score);//将三项数据输入到文件当中,我先将数据存储在数组当中。
}
fclose(fp);
}


void GetDataFromFile(student array[], const char*filename){
FILE*fp=fopen(filename,"r");
int i=0;
while (fscanf(fp,"%s %d %d\n",array[i].name,&array[i].age,&array[i].score)!=EOF)//从文件中读取数据并将其存储在数组中。
{
  printf("%s %d %d\n",array[i].name,array[i].age,array[i].score);//输出数据
  i++;
}

fclose(fp);

}

在这两个函数中,需要传入的参数是文件名,结构体数组,向文件里输出还需要数组大小。

我有这样的感觉:之前用printf是输出,scanf是输入;但是在文件中,给人的感觉是:fprintf是输入,fscanf也是输入。其实本质上,fprintf只是把输出的地点换成了文件这个不可见的位置,输出之后相当于把数据留在了文件中;而fscanf则是把数据从文件中读出,再存储到变量当中。本质上只是从屏幕到文件的转变。

使用时需要注意的点是:你在fprintf用了怎样的格式去把数据输入到文件中,你就应当在fscanf中用怎样的格式去输出数据,因为fscanf是会读取类似于空格,\n,\t这样的字符的,这是fscanf于scanf不同的地方。

这是主函数的操作以及最后的输出,大家可以拿去验证一下,这两个函数也是可以直接用的~

int main(){

student array[3]={{"ww",19,100},{"qq",18,111},{"mm",20,99}};//初始化结构体数组

InputDataToFile(array,"newfile.file",3);

GetDataFromFile(array,"newfile.file");

return 0;
}

字节流读写:fwrite,fread

这两个函数是按照字节来进行读写的,使用的范围更加广泛。

先来看一下函数原型是什么样子的:

size_t fwrite

(const void *__restrict__ _Str,

size_t _Size,

size_t _Count,

FILE *__restrict__ _File)

下面来解释一下fwrite的每行的参数的含义

第一个,是一个空指针,指向你要向文件中输入的内容的首地址(注意,这里可以是任意的数据类型!

第二个,代表的是你要输入多少长度;

第三个,代表输入的次数;

第四个,代表要输入的文件的指针。

那么其实fread的内部结构也是一样,也是四个参数,意思完全一样,第一个参数就是你要把数据读出来以后存储到的内存的首地址。

还是以上面的结构体数组为例,我们使用这两个函数来进行读写操作。

先给出第一种fwrite的方法:一个一个数据的读入。

student array[3]={{"zzh",19,100},{"ppc",18,111},{"cxk",20,99}};
FILE*fp=fopen("newfile.file","w");
for(int i=0;i<3;i++){
fwrite(&array[i],sizeof(student),1,fp);
}
fclose(fp); //把数据存储进入newfile里面。

FILE*fp1=fopen("newfile.file","r");
student readarray[3];
fread(&readarray[0],sizeof(student),1,fp1);
fprintf(stdout,"%s %d %d\n",readarray[0].name,readarray[0].age,readarray[0].score);//我是把他在屏幕上打印出来了
fclose(fp1);//从newfile中读取一个数据并把它存在新数组的元素readarray里面。

第二种方法是:一次性读入所有数组的元素,只需要把第三个参数——也就是读入几个改成数组的大小即可。

fwrite(array,sizeof(student),3,fp);

 相当于是每次找到一个结构体的内存大小,然后写入三个即可。

因此我们使用这个函数可以对任何类型的文件进行存储,比如图片文件jpg,我们也可以把它用fread函数存储在一个整型,字符型等等的数组中,然后再用这个数组,用fwrite把它存放到另外一个jpg文件中,中途我们甚至还可以对数组中的元素进行修改,给图片加密,这很麻烦我就不再写代码来演示了。

不过当我们的文件很大的时候,就不能使用数组了,比如一个几十MB的文件,不能使用静态的数组,必须要使用动态内存申请!!

文件指针操作函数:ftell,fseek

ftell函数和fseek函数在我看来是对文件指针的量化和指针移动的显化,因为我们知道,在平常一般使用的时候每调用一次fopen函数,文件指针都会自动的移动数据类型的大小,这一过程不需要我们自己操作。因此这两个函数是对指针操作的一个具化。

ftell函数的参数只有文件指针一个,他返回的是文件指针现在的位置与文件开头位置的距离。

fseek函数的原型是:int fseek(FILE *_File, long _Offset, int _Origin);这个函数的作用是将指针从origin大小的位置移动offset大小个字节。其中origin在编译器里有三种位置:

分别代表了:当前位置,文件结尾位置,文件开始位置。如果操作后指针仍在文件的大小范围之内,则返回1,;否则返回0。

根据这两个函数,我们知道大文件的fread是需要动态申请内存的,因此我们需要得到文件的所占字节数,因此我们使用这两个函数来写一个文件大小读取函数。

long GetSizeOfFile(const char*filename){
FILE*fp=fopen(filename,"r");
fseek(fp,0,SEEK_END);//将指针移动从文件的末尾移动0个字节,还是末尾
long size=ftell(fp);  //返回指针移动的字节数。
fclose(fp);
return size;
}

输出成功啦!

还想强调一点,读和写,这两个操作是分开的!把数据写进文件的时候的文件指针fp=fopen...,在后面从文件中读出的时候的已经是在文件末尾了!因为在这其中我们的函数会自动对指针进行移动的操作(前面所有函数,fgetc,fgets...).所以独读出(使用fputc,fputs)的时候得另外设置一个指针来使起回到文件开头哦。

以上就是文件的操作,一些函数的介绍与功能应用,希望对uu们有帮助~~

笔记整理不易,给个一键三连再走吧~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/445227.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot的招聘网站

基于jspmysqlSpring的SpringBoot招聘网站项目&#xff08;完整源码sql&#xff09; 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》…

网络编程总结

文章目录 1.浏览器输入一个 url 中间经历的过程2.TCP,UDP 的区别3.HTTP 协议HTTP 协议有哪些部分组成&#xff1f;响应状态码GET 和 POST 的区别什么是幂等的什么是 HTTP 的长链接cookie 和 session 的区别TCP socket 编程原理 4.IO 多路复用五种 IO 模型如何提升服务器的并发能…

Ubuntu 基本操作-嵌入式 Linux 入门

在 Ubuntu 基本操作 里面基本就分为两部分&#xff1a; 安装 VMware 运行 Ubuntu熟悉 Ubuntu 的各种操作、命令 如果你对 Ubuntu 比较熟悉的话&#xff0c;安装完 VMware 运行 Ubuntu 之后就可以来学习下一章节了。 1. 安装 VMware 运行 Ubuntu 我们首先来看看怎么去安装 V…

2.4_4 死锁的检测和解除

文章目录 2.4_4 死锁的检测和解除&#xff08;一&#xff09;死锁的检测&#xff08;二&#xff09;死锁的解除 总结 2.4_4 死锁的检测和解除 如果系统中既不采取预防死锁的措施&#xff0c;也不采取避免死锁的措施&#xff0c;系统就很可能发生死锁。在这种情况下&#xff0c;…

通过Annotation将用户操作记录到数据库表功能实现

一、背景 在用户对我们所开发的系统访问的时候&#xff0c;需要我们的系统具有强大的健壮性&#xff0c;使得给与用户的体验感十足。在业务开发的过程中&#xff0c;我们通过将几个相关的操作绑定成一个事件&#xff0c;使得安全性以及数据的前后一致性得到提高。但是在溯源方面…

Linux第74步_“设备树”下的LED驱动

使用新字符设备驱动的一般模板&#xff0c;以及设备树&#xff0c;驱动LED。 1、添加“stm32mp1_led”节点 打开虚拟机上“VSCode”&#xff0c;点击“文件”&#xff0c;点击“打开文件夹”&#xff0c;点击“zgq”&#xff0c;点击“linux”&#xff0c;点击“atk-mp1”&am…

三角形费马点及深入拓展

三角形费马点及深入拓展 一、费马点的定义 三角形内部满足到三个顶点距离之和最小的点&#xff0c;称为费马点。 二、费马点的证明 比较麻烦的一件事情是&#xff0c;当我们考虑一个三角形的费马点时&#xff0c;我们需要将三角形分为两类: ①三个内角均小于120的三角形 ②有…

【SQL】185. 部门工资前三高的所有员工(窗口函数dense_rank();区分rank()、row_number())

前述 推荐阅读&#xff1a;通俗易懂的学会&#xff1a;SQL窗口函数 题目描述 leetcode题目 185. 部门工资前三高的所有员工 思路 先按照departmentId分组&#xff0c;再按照salary排序 >窗口函数dense_rank() over() select B.name as Department,A.name as Employee,A…

Python 初步了解urllib库:网络请求的利器

目录 urllib库简介 request模块 parse模块 error模块 response模块 读取响应内容 获取响应状态码 获取响应头部信息 处理重定向 关闭响应 总结 在Python的众多库中&#xff0c;urllib库是一个专门用于处理网络请求的强大工具。urllib库提供了多种方法来打开和读取UR…

试用期自我总结报告10篇

试用期自我总结报告&#xff08;篇1&#xff09; 一转眼试用期的时间飞快就过去了&#xff0c;在这段时间里我学习到了很多&#xff0c;也把自己在过去学习的东西得已融会贯通。能够来到幼儿园里成为一名老师是我一直以来的目标&#xff0c;而我也终于完成了自己的目标&#x…

Springboot+vue的医院药品管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的医院药品管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09…

如何在RTMP推送端和RTMP播放端支持Enhanced RTMP H.265(HEVC)

技术背景 时隔多年&#xff0c;在Enhancing RTMP, FLV With Additional Video Codecs And HDR Support&#xff08;2023年7月31号正式发布&#xff09;官方规范出来之前&#xff0c;如果RTMP要支持H.265&#xff0c;大家约定俗成的做法是扩展flv协议&#xff0c;CDN厂商携手给…

React-Mock数据

1.概念 说明&#xff1a;React中使用Mock数据主要是为了模拟后端接口和数据&#xff0c;以便前端开发可以在没有实际后端支持的情况下进行。 2.实现步骤 2.1安装 npm i -D json-server 2.2准备json文件 {"list":[{"name":"李四","age&q…

【Python】进阶学习:OpenCV--一文详解cv2.namedWindow()

【Python】进阶学习&#xff1a;OpenCV–一文详解cv2.namedWindow() &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望…

编码器-解码器模型(Encoder-Decoder)

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 编码器-解码器模型简介 Encoder-Decoder算法是一种深度学习模型结构&#xff0c;广泛应用于自然语言处理&#xff08;NLP&#xff09;、图像处理…

mybatis-plus整合spring boot极速入门

使用mybatis-plus整合spring boot&#xff0c;接下来我来操作一番。 一&#xff0c;创建spring boot工程 勾选下面的选项 紧接着&#xff0c;还有springboot和依赖我们需要选。 这样我们就创建好了我们的spring boot&#xff0c;项目。 简化目录结构&#xff1a; 我们发现&a…

java中移位<< >> <<< |数据类型转换

移位 x64转换二进制&#xff1a;100 0000 左移2位 &#xff1a; 1000 0000 0 对应十进制 i 256 >>右移 <<左移 >>无符号位右移 关于右移一位相当于整除2 数据类型及其转换 基本数据类型&#xff0c;数据类型范围 byte(-128~127)&#xff08;-2^7~2…

unity学习(54)——选择角色界面--解析赋值服务器返回的信息1

1.decode这种照猫画虎的工作 把逆向出来UserHandler.cs中的内容&#xff0c;融到自建客户端的MessageManager.cs中&#xff1a; 2.此时登录账号&#xff0c;马上显示当前账号下已有三名角色&#xff1a; 此时返回数据包中的command的值是1&#xff1a; 3.当注册玩家数超过三名…

pytorch的理解

工具的查看与使用帮助 1. dir import torch torch.cuda.is_available()dir(torch) dir(torch.cuda) #可以看到有"is_available" 2. help help(torch.cuda.is_available)

python基础——条件判断和循环【if,while,for,range】

&#x1f4dd;前言&#xff1a; 这篇文章主要讲解一下条件判断语句if和循环语句while&#xff0c;for在python中需要注意的地方。 建议已有一定了解&#xff08;对语句的执行逻辑清楚&#xff09;的读者观看&#xff0c;如果对条件判断和循环的执行逻辑不太清楚&#xff0c;也可…
最新文章