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.hqwc.cn/news/526247.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【HarmonyOS】ArkTS-联合类型

目录 联合类型实例 联合类型 联合类型是一种灵活的数据类型&#xff0c;它修饰的变量可以存储不同类型的数据。 语法&#xff1a;let 变量: 类型1 | 类型2 | 类型3 值 基于联合类型&#xff0c;变量可存不同类型数据 实例 // 需求&#xff1a;定义一个变量&#xff0c;存放…

Building Systems with the ChatGPT API

Building Systems with the ChatGPT API 本文是 https://www.deeplearning.ai/short-courses/building-systems-with-chatgpt/ 这门课程的学习笔记。 文章目录 Building Systems with the ChatGPT APIWhat you’ll learn in this course Language Models, the Chat Format and…

【编译原理】1、python 实现一个 JSON parser:lex 词法分析、parser 句法分析

文章目录 一、实现 JSON lexer&#xff08;词法解析器&#xff09;二、lex 词法分析2.1 lex string 解析2.2 lex number 解析2.3 lex bool 和 null 解析 三、syntax parser 句法分析3.1 parse array 解析数组3.2 parse object 解析对象 四、封装接口 一、实现 JSON lexer&#…

运维随录实战(12)之node版本管理工具nvm

1,下载安装nvm 可以去其 github 主页下在,地址为 github.com/coreybutler…会看到有很多个文件可供选择: 这里稍做下解释: nvm-noinstall.zip: 这个是绿色版本,不需要安装,但是使用之前需要配置环境变量;nvm-setup.zip:推荐下载这个包,无需配置就可以使用;Source …

Mint_21.3 drawing-area和goocanvas的FB笔记(七)

FreeBASIC gfx 基本 graphics 绘图 8、ScreenControl与屏幕窗口位置设置 FreeBASIC通过自建屏幕窗口摆脱了原来的屏幕模式限制&#xff0c;既然是窗口&#xff0c;在屏幕坐标中就有它的位置。ScreenControl GET_WINDOW_POS x, y 获取窗口左上角的x, y位置&#xff1b;ScreenC…

深度学习+感知机

深度学习感知机 1感知机总结 2多层感知机1XOR2激活函数3多类分类总结 3代码实现 1感知机 是个很简单的模型,是个二分类的问题。 感知机&#xff08;perceptron&#xff09;是Frank Rosenblatt在1957年提出的一种人工神经网络&#xff0c;被视为一种最简单形式的前馈神经网络&…

【亲测有效】解决三月八号ChatGPT 发消息无响应!

背景 今天忽然发现 ChatGPT 无法发送消息&#xff0c;能查看历史对话&#xff0c;但是无法发送消息。 可能的原因 出现这个问题的各位&#xff0c;应该都是点击登录后顶部弹窗邀请 [加入多语言 alapha 测试] 了&#xff0c;并且语言选择了中文&#xff0c;抓包看到 ab.chatg…

Linux篇:文件系统和软硬连接

一 前置知识 文件文件内容文件属性 磁盘上存储文件存文件的内容&#xff08;数据块&#xff09;存文件的属性&#xff08;inode&#xff09; Linux的文件在磁盘中存储是将属性和内容分开存储的。文件内容的存储是给每个文件分配一块空间&#xff0c;此空间就叫数据块。文件属性…

C++primer -拷贝控制

拷贝控制成员&#xff1a;类通过五种函数来控制拷贝、移动、赋值和销毁&#xff1a;拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符、析构函数 合成拷贝控制成员&#xff1a; 若一个类未显式定义拷贝控制成员&#xff0c;编译器会自动生成合成版本&#xff1b; …

ActiveRAG—主动学习

原文地址&#xff1a;ActiveRAG — Active Learning 2024 年 2 月 26 日 大型语言模型&#xff08;LLM&#xff09;的出现开创了对话式人工智能的新时代。这些模型可以生成非常类似人类的文本&#xff0c;并且比以往更好地进行对话。然而&#xff0c;他们仍然面临着仅仅依靠预先…

JVM知识整体学习

前言&#xff1a;本篇没有任何建设性的想法&#xff0c;只是我很早之前在学JVM时记录的笔记&#xff0c;只是想从个人网站迁移过来。文章其实就是对《深入理解JVM虚拟机》的提炼&#xff0c;纯基础知识&#xff0c;网上一搜一大堆。 一、知识点脑图 本文只谈论HotSpots虚拟机。…

TYPE C模拟耳机POP音产生缘由

关于耳机插拔的POP音问题&#xff0c;小白在之前的文章中讲述过关于3.5mm耳机的POP音产生原因。其实这类插拔问题的POP音不仅仅存在于3.5mm耳机&#xff0c;就连现在主流的Type C模拟耳机的插拔也存在此问题&#xff0c;今天小白就来讲一讲这类耳机产生POP音的缘由。 耳机左右…