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

news2025/2/26 7:28:53

突然发现自己的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.coloradmin.cn/o/1504850.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

了解 HTTPS 中间人攻击:保护你的网络安全

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

C语言指针从入门到基础详解(非常详细)

1.内存和地址 我们知道电脑中的CPU在处理数据的时候需要在内存中读取数据处理后的数据也会放在内存中。把内存划分为一个个的内存单元每个单元的大小是一个字节。每个字节都有它对应的编号也就是它的地址&#xff0c;以便CPU可以快速的找到一个内存空间。C语言中我们把地址叫做…

深入浅出计算机网络 day.1 概论① 信息时代的计算机网络

我想&#xff0c; 我不会暗下来的&#xff0c; 生命是周而复始的橙黄橘绿时 —— 24.3.9 内容概述 计算机网络的各类应用 计算机网络带来的负面问题 我国互联网发展情况 一、计算机网络的各类应用 1.信息浏览和发布 2.通信和交流 3.休闲和娱乐 4.资源共享…

Canal安装使用

一 Canal介绍 canal是阿里巴巴旗下的一款开源项目&#xff0c;纯Java开发。基于数据库增量日志解析&#xff0c;提供增量数据订阅&消费&#xff0c;目前主要支持了MySQL&#xff08;也支持mariaDB&#xff09;。 背景 早期&#xff0c;阿里巴巴B2B公司因为存在杭州和美国…

MyBatis3源码深度解析(七)JDBC单连接事务

文章目录 前言2.7 JDBC单连接事务2.7.1 事务的开启与提交2.7.2 事务隔离级别2.7.2.1 并发访问问题&#xff08;1&#xff09;脏读&#xff08;2&#xff09;不可重复读&#xff08;3&#xff09;幻读 2.7.2.2 事务隔离级别&#xff08;1&#xff09;TRANSACTION_NONE&#xff1…

JVM内存问题排错最佳实践

写在文章开头 上一篇的文章中分享了一个入门级别的调优实践,收到很多读者的好评,所以笔者今天再次分享一个进阶一点的案例,希望对近期在面试的读者对于JVM这一块的实践经验有所帮助。 Hi,我是 sharkChili ,是个不断在硬核技术上作死的 java coder ,是 CSDN的博客专家 ,…

光伏数字化管理平台:驱动绿色能源革命的智能化引擎

随着全球对可再生能源需求的不断增长&#xff0c;光伏产业已经成为推动绿色能源革命的重要力量。在这个背景下&#xff0c;光伏数字化管理平台应运而生&#xff0c;以其强大的数据处理、实时监控和智能优化功能&#xff0c;为光伏电站的运营管理和维护带来了革命性的变革。 光伏…

有源电桥电路

有源电桥电路 有源电桥由A3运放的正向输入端与负向输入端电压相等且为零可知&#xff1a;G点&#xff08;待测阻抗Zx与被测阻抗Rs的连接点&#xff09;电平一直为零&#xff0c;也就是平衡点虚地点&#xff0c;Ux与Us也就变成参照虚地点的绝对相量电压。并且根据运放的虚断原理…

7-16 计算符号函数的值

对于任一整数n&#xff0c;符号函数sign(n)的定义如下&#xff1a; 请编写程序计算该函数对任一输入整数的值。 输入格式: 输入在一行中给出整数n。 输出格式: 在一行中按照格式“sign(n) 函数值”输出该整数n对应的函数值。 输入样例1: 10输出样例1: sign(10) 1输入样…

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

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

springboot255基于spring boot的疫情信息管理系统

疫情信息管理系统的设计与实现 摘要 近年来&#xff0c;信息化管理行业的不断兴起&#xff0c;使得人们的日常生活越来越离不开计算机和互联网技术。首先&#xff0c;根据收集到的用户需求分析&#xff0c;对设计系统有一个初步的认识与了解&#xff0c;确定疫情信息管理系统…

人工智能|机器学习——DBSCAN聚类算法(密度聚类)

1.算法简介 DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法&#xff0c;簇集的划定完全由样本的聚集程度决定。聚集程度不足以构成簇落的那些样本视为噪声点&#xff0c;因此DBSCAN聚类的方式也可以用于异常点的检测。 2.算法原…

Xss-labs-master 1-16关

第一关 <?php ini_set("display_errors", 0); $str $_GET["name"]; echo "<h2 aligncenter>欢迎用户".$str."</h2>"; ?> <center><img srclevel1.png></center> <?php echo "&l…

【NR技术】 3GPP支持无人机服务的关键性能指标

1 性能指标概述 5G系统传输的数据包括安装在无人机上的硬件设备(如摄像头)收集的数据&#xff0c;例如图片、视频和文件。也可以传输一些软件计算或统计数据&#xff0c;例如无人机管理数据。5G系统传输的业务控制数据可基于应用触发&#xff0c;如无人机上设备的开关、旋转、升…

实时智能应答3D数字人搭建

语音驱动口型的算法 先看效果&#xff1a; 你很快就可以帮得上我了 FACEGOOD 决定将语音驱动口型的算法技术正式开源&#xff0c;这是 AI 虚拟数字人的核心算法&#xff0c;技术开源后将大程度降低 AI 数字人的开发门槛。FACEGOOD是一家国际领先的3D基础软件开发商&#xff0c;…

【sgExcelGrid】自定义组件:简单模拟Excel表格拖拽、选中单元格、横行、纵列、拖拽圈选等操作

特性&#xff1a; 可以自定义拖拽过表格可以点击某个表格&#xff0c;拖拽右下角小正方形进行任意方向选取单元格支持选中某一行、列支持监听selectedGrids、selectedDatas事件获取选中项的DOM对象和数据数组支持props自定义显示label字段别名 sgExcelGrid源码 <template&g…

MySQL主从读写分离之Proxysql(openEuler版)

实验目的&#xff1a; 基于proxysql实现MySQL的主从读写分离。 实验过程&#xff1a; 前期准备&#xff1a; 一共有四台虚拟机&#xff0c;其中三台为配置好的一主两从虚拟机&#xff0c;还有一台干净的虚拟机用来配置proxysql。 主机名地址master192.168.27.137node1192.…

如何在Windows系统使用固定tcp公网地址ssh远程Kali系统

文章目录 1. 启动kali ssh 服务2. kali 安装cpolar 内网穿透3. 配置kali ssh公网地址4. 远程连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 简单几步通过[cpolar 内网穿透](cpolar官网-安全的内网穿透工具 | 无需公网ip | 远程访问 | 搭建网站)软件实现ssh 远程连接kali! …

【机器学习300问】30、准确率的局限性在哪里?

一、什么是准确率&#xff1f; 在解答这个问题之前&#xff0c;我们首先得先回顾一下准确率的定义&#xff0c;准确率是机器学习分类问题中一个很直观的指标&#xff0c;它告诉我们模型正确预测的比例&#xff0c;即 还是用我最喜欢的方式&#xff0c;举例子来解释一下&#xf…

业务随行简介

定义 业务随行是一种不管用户身处何地、使用哪个IP地址&#xff0c;都可以保证该用户获得相同的网络访问策略的解决方案。 背景 在企业网络中&#xff0c;为实现用户不同的网络访问需求&#xff0c;可以在接入设备上为用户部署不同的网络访问策略。在传统园区网络中&#xf…