写点什么

【C 语言】深度剖析文件操作 [进阶篇 _ 复习专用]

作者:Dream-Y.ocean
  • 2022 年 9 月 19 日
    广东
  • 本文字数:5607 字

    阅读完需:约 18 分钟

【C语言】深度剖析文件操作 [进阶篇_ 复习专用]

前情提要


本章节就进入 C 语言的核心:深度剖析 C 语言文件操作


接下来我们即将进入一个全新的空间,对代码有一个全新的视角~


以下的内容一定会让你对 C 语言有一个颠覆性的认识哦!!!


以下内容干货满满,跟上步伐吧~




💡本章重点


  • 文件

  • 文本文件操作函数

  • 文本文件和二进制文件

  • 文件缓存区



🍞一.文件

🥐Ⅰ.为什么使用文件

在我们已知 C 语言程序是无法保存数据的,在程序退出时数据便自然不在了,这是因为程序运行时存储的数据都在临时空间上,一旦程序结束,空间便被释放销毁,所以数据无法保存


❓如果我们想将数据持久化,我们该怎么办呢


➡️以下,便引出我们的文件操作啦~


  • 使用文件可以将数据直接放到电脑硬盘上,做到数据的持久化

🥐Ⅱ.什么是文件

💡一般我们称:


  • 磁盘上的文件是文件


👉通过上述我们可了解到:


文件分为两种(从文件功能的角度来分类):


  • 1️⃣程序文件

  • ① 源程序文件(后缀为.c)

  • ②目标文件(windows 环境后缀为.obj)

  • ③可执行程序(windows 环境后缀为.exe)

  • 2️⃣数据文件

  • ①文件的内容不一定是程序,而是程序运行时读写的数据

  • ②比如:程序运行需要从中读取数据的文件,或者输出内容的文件

🥐Ⅲ.文件名

💡一个文件要有一个唯一的文件标识,以便用户识别和引用


➡️文件名包含三部分:


  • 文件路径+文件名主干+文件后缀


👉Eg: c: \ code \ test.txt

🥯Ⅳ.总结

综上: 就是对文件的概述了~


但我们如何在程序中实际操作文件呢?


以下便引出了我们的文件文本操作函数



🍞二.文本文件操作函数

🥐Ⅰ.文件指针

💡在 C 语言中,每当我们想对文件进行操作时:


  • 1️⃣文件先在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息【如文件的名字,文件状态及文件当前的位置等】

  • 2️⃣而文件信息区在 C 语言中实则是保存在一个系统声明为FILE结构体变量


特别注意:


  • 每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节


➡️而期间 C 语言为了更加方便的对FILE这个存储文件信息的结构体变量进行操作,我们便可以使用文件指针变量


FILE* pf; //文件指针变量
复制代码


⬆️定义pf是一个指向FILE类型数据的指针变量


  • 这样我们就可以使pf指向某个文件的文件信息区(是一个结构体变量),即指向FILE的结构体变量


  • 一般定义FILE*的指针是为了更方便于我们利用文件指针维护/访问这个结构体变量【文件信息区】


综上:


  • 我们对文件进行操作,实际上是利用文件指针这个结构体变量对文件信息区FILE这个结构体变量】进行操作

  • 也就是说:通过文件指针变量能够找到与它关联的文件

🥐Ⅱ.文件的打开和关闭

🧇1.fopen 函数


FILE * fopen ( const char * filename, const char * mode );
复制代码


💡fopen函数的作用: 操控程序打开磁盘中的文件


  • 函数的参数:

  • filename为想要打开文件的文件名

  • mode为文件的打开方式

  • 函数的返回值: 返回的是指向此文件的文件信息区的起始地址的指针,指针类型为FILE*


➡️函数工作原理:


在打开文件的同时,会返回一个FILE*的指针变量指向该文件,相当于建立了指针和文件的关系,我们后续便可以使用这个指针进行文件的操作


  • 文件打开成功,则返回一个指向此文件信息区的起始地址的指针

  • 文件打开失败,则返回NULL


❗此处类似于动态开辟内存函数,因为存在打开失败的情况,我们不能贸然直接使用返回的指针,我们应要先对返回的指针进行判断

🧇2.fclose 函数


int fclose ( FILE * stream );
复制代码


💡fclose函数的作用: 关闭所操作的文件


  • 函数的参数: stream为想要关闭的文件的文件指针

  • 函数的返回值: int


➡️函数工作原理:


类似于free的操作,只需要输入文件指针,fclose便会关闭文件指针指向的文件信息区


  • 成功关闭文件,则会返回0

  • 关闭失败,则返回EOF【即-1

🧇3.文件打开使用方式

综上: 我们已经了解了文件的打开和关闭的操作函数,接下来让我们看看在使用fopen函数的时候有什么使用方式



❗其中最常使用的是前三个,我们需要记住哦~


💥特别注意: 要对文件进行操作,一般最开始先打开文件,最后一定要记得关闭文件【即fopenfclose是要搭配来用的,缺一不可】

🧇4. 例子

👉Eg:


int main(){    //打开文件    FILE* pf = fopen ("test.txt","w");        //判断文件指针    if (pFile==NULL)    {        perror("fopen");        return 1;    }
//文件使用 //...
//关闭文件 fclose(pf); pf = NULL; return 0;}
复制代码

🥐Ⅲ.文件的顺序读写


❗以上的输入/输出:指的是对文件进行输入(写入)、输出(读取)


➡️以下为了让大家对上述的函数有更具体地印象,以下内容将成对函数地进行讲解~



❤️fputc 函数


int fputc ( int character, FILE * stream );
复制代码


💡fputc函数的作用: 对文件进行单个字符的写入


  • 函数的参数:

  • character为想要写入文件的字符

  • stream为指向单个字符写入的文件的地址的指针

  • 函数的返回类型: int


➡️函数工作原理:


  • 函数会将输入的字符写入到文件指针指向的文件中


👉示例:



特别注意:


  • 每次以"w"的打开方式打开文件关闭文件后,下次进入程序再用"w"的方式打开的话,文件的内容被重置【即上次写入的内容全部清除了】

❤️fgetc 函数


int fgetc ( FILE * stream );
复制代码


💡fgetc函数的作用: 读取文件的一个字符内容


  • 函数的参数: stream为指向想要读取字符的文件的地址的指针

  • 函数的返回类型: int


➡️函数工作原理:


  • 函数会每次读取文件中的一个字符

  • 返回的是读取的字符的ASCII


特别注意:


  • 每次使用fgetc函数,读取文件中的一个字符后,文件指针会自动偏移一下,指向下一个字符,方便读取下一个字符


👉示例:




🧡fputs 函数


int fputs ( const char * str, FILE * stream );
复制代码


💡fputs函数的作用: 向文件内写入字符串


  • 函数的参数:

  • str为想要写入的字符串

  • stream为指向写入字符串的文件的地址的指针

  • 函数的返回值: int


➡️函数工作原理:


  • 函数会将输入的字符写入到文件指针指向的文件中


👉示例:


🧡fgets 函数


char * fgets ( char * str, int num, FILE * stream );
复制代码


💡fgets函数的作用: 读取文件中的字符串


  • 函数的参数:

  • str为将从文件中读取的字符串,拷贝到str指向的空间中【一般为数组】

  • num为读取字符串的个数

  • stream为指向想要读取文件的地址的指针

  • 函数的返回值: char*


➡️函数工作原理:


  • 函数将会读取文件中num个字符个数的字符串


特别注意:


  • 1️⃣实际读取的字符个数的字符串会比num少一个【因为需要预留一个位置给函数放\0str中】

  • 2️⃣读取的过程类似于fgetc,文件指针一直在随着读取的字符往后走,本次读取过的就不能在读取了,只能往后读取


👉示例:




💛fprintf 函数


int fprintf ( FILE * stream, const char * format, ... );
复制代码


💡fprintf函数的作用: 将格式化变量的数据写入文件


  • 函数的参数:

  • stream为指向写入格式化数据的文件的地址的指针

  • format为写入数据的格式【Eg:%s%d……】

  • ...为数据的来源

  • 函数的返回值: int


➡️函数工作原理:


  • 函数将格式化数据写入到文件中


此处我们可以对比print函数:


此处我们不难发现:printffprintf之间有两个参数是一样的,这样我们也就更好理解什么是格式化数据了,我们只要回想一下我们平时如何用printf输出变量的数据就知道了


👉示例:


💛fscanf 函数


int fscanf ( FILE * stream, const char * format, ... );
复制代码


💡fscanf函数的作用: 格式化的方式读取文件中的数据


  • 函数的参数:

  • stream为指向格式化方式读取数据的文件的地址的指针

  • format为读取数据的格式【Eg:%s%d……】

  • ...为格式化数据写入的地方

  • 函数的返回值: int


➡️函数工作原理:


  • 函数将以格式化的方式读取文件中的数据


👉示例:


🫓 总结

综上: 就是适用于所有输入、输出流对文件进行文本的输入、输出操作函数啦~


➡️简单来说: 就是对文件进行文本的输入、输出



💚fwrite 函数


size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
复制代码


💡fwrite函数的作用: 对文件进行二进制的写入数据


  • 函数的参数:

  • ptr为指向存储要写入到文件的数据的指针

  • size为‎要写入的数据的总大小【单位:字节

  • count为最多写几个size大小为单位的数据【单位:字节

  • stream为指向写入数据的文件的地址的指针

  • 函数的返回值: size_t


➡️函数工作原理:


  • 函数将每次以count大小个字节,从ptr 中拿取数据以二进制的方式写入文件中,一共写入size个字节


👉示例:



💥特别注意:


  • 这里的fwrite函数的第三个参数count1是因为前面size是计算整个结构体的大小,即以整个结构体为单位,所以这里1的意思是最多只写入一个这样整个结构体大小的数据


❗实际上105.5f已经以二进制的方式写入到文本,只是文本的格式显示不出来,所以才显示乱码

💚fread 函数


size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
复制代码


💡fread函数的作用: 对文件进行二进制的读取数据


  • 函数的参数:

  • ptr为指向要读取的文件的数据的指针

  • 函数的返回值: size_t


➡️函数工作原理:


  • 函数将每次以count大小个字节,读取文件中的二进制数据到ptr所指向的空间,一共读取size 字节


👉示例:


🫓 总结

综上: 就是适用于文件输入、输出流对文件进行二进制的输入、输出操作函数啦~


➡️简单来说: 就是对文件进行二进制的输入、输出



💙sprintf 函数


int sprintf ( char * str, const char * format, ... );
复制代码


💡sprintf函数的作用: 把一个格式化的数据写到一个字符串里


  • 函数的参数:

  • stream为指向将格式化数据写入到字符串的地址的指针

  • format为写入数据的格式【Eg:%s%d……】

  • ...为数据的来源

  • 函数的返回值: int


➡️简单来说:


  • 就是将格式化数据转换成字符串的格式进行打印、输出


👉示例:


💙sscanf 函数


int sscanf ( const char * s, const char * format, ...);
复制代码


💡sscanf函数的作用: 把一个字符串读出一个格式化的数据


  • 函数的参数:

  • stream为指向存储字符串的地址的指针

  • format为写入数据的格式【Eg:%s%d……】

  • ...为格式化数据写入的地方

  • 函数的返回值: int


➡️简单来说:


  • 就是将字符串中的数据以格式化的方式读取出来


👉示例:


🫓 总结

综上: 就是数据在格式化形式字符串形式之间的转换啦~


➡️简单来说: 上述的函数对比于printfscanf都多了个s,这个s的意思就是string,证明上述的函数都是对字符串进行转换啦~

🥐Ⅳ.文件的随机读写

💜fseek 函数


int fseek ( FILE * stream, long int offset, int origin );
复制代码


💡fseek函数的作用: 根据文件指针的位置和偏移量来定位文件指针


  • 函数的参数:

  • stream为指向文件的地址的指针

  • offset为文件指针的偏移量

  • origin为文件指针偏移量的相对起始地址

  • 函数的返回值: int


➡️函数工作原理:


  • 函数将会使文件指针在选定的起始位置origin处偏移offset个位置,到达外面想让文件指针到达的位置进行访问


C 语言提供了三个origin(起始位置):


  • 1️⃣SEEK_SET:“文件的起始位置处” 开始偏移

  • 2️⃣SEEK_CUR:“当前文件指针的位置” 开始偏移

  • 3️⃣ SEEk_END:“文件末尾处” 开始偏移


👉示例:


🤎ftell 函数


long int ftell ( FILE * stream );
复制代码


💡ftell函数的作用: 返回文件指针相对于起始位置的偏移量


  • 函数的参数:

  • stream为指向文件的地址的指针

  • 函数的返回值: int


➡️函数工作原理:


  • 函数将会返回现在文件指针相对于文件的起始位置的偏移量


👉示例:


🖤rewind 函数


void rewind ( FILE * stream );
复制代码


💡rewind函数的作用: 让文件指针的位置回到文件的起始位置


  • 函数的参数:

  • stream为指向文件的地址的指针

  • 函数的返回值: void


➡️函数工作原理:


  • 将文件指针的位置重置


👉示例:


🫓 总结

综上: 就是可以让文件指针进行随机读取的函数啦~


➡️简单来说: 有了上述函数,就可以让文件指针想读哪里就读哪~



🍞三.文本文件和二进制文件

💡简单来说:


  • 数据在内存中以二进制的形式存储,如果不加转换的输出,就是二进制文件

  • 如果加以ASCII字符的形式转换,那存储的文件就是文本文件


特别注意:


  • 1️⃣字符使一律以ASCII形式存储【这也是为什么上述我们讲的二进制读取和文本读取字符的效果一样】

  • 2️⃣数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储


👉Eg: 如有整数 10000


  • 如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节)

  • 二进制形式输出,则在磁盘上只占4个字节




🍞四.文件读取结束的判定

🥐Ⅰ.feof 函数


int feof ( FILE * stream );
复制代码


💡feof函数的作用: 判断文件结束的时候是否是因为遇到文件尾结束


  • 函数的参数:

  • stream为指向文件的地址的指针

  • 函数的返回值: int


➡️函数工作原理:


  • 1️⃣若文件结束时因为遇到文件尾结束的,则返回非0

  • 2️⃣若文件结束不是因为遇到文件尾结束的,则返回0


👉简单来说:


  • feof就是文件结束的前提下,判断文件时因为读取失败而结束的,还是遇到文件尾结束


特别注意:


  • 1️⃣feof只能判断是哪种原因结束的,但不能用来判断文件是否结束【因为这个是feof使用的前提,不能作为结论来使用】


💥文件读取是否结束,我们根据如下来判断:


  • 1️⃣文本文件:

  • fgetc在读取结束时,返回EOF

  • fgets在读取结束时,返回NULL

  • 2️⃣二进制文件:

  • fread在读取结束时,返回一个小于实际要读的个数的值


综上:


  • feof就是判断文件结束是不是因为上述的三个结束标志造成的



🍞五.文件缓冲区

💡什么是文件缓冲区:


  • 所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”


特别注意:


  • 1️⃣即从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上

  • 2️⃣如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)

  • 3️⃣缓冲区的大小根据C编译系统决定的。



综上:


  • 因为有缓冲区的存在,C 语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件,才能对文件读写正常

  • 否则,如果不做,可能导致读写文件的问题



🫓总结

综上,我们基本了解了 C 语言中的“文件操作”:lollipop:的知识啦~~


恭喜你的内功又双叒叕得到了提高!!!


感谢你们的阅读:satisfied:


后续还会继续更新:heartbeat:,欢迎持续关注:pushpin:哟~


:dizzy:如果有错误❌,欢迎指正呀:dizzy:


:sparkles:如果觉得收获满满,可以点点赞👍支持一下哟~:sparkles:



发布于: 刚刚阅读数: 5
用户头像

Dream-Y.ocean

关注

还未添加个人签名 2022.06.17 加入

还未添加个人简介

评论

发布
暂无评论
【C语言】深度剖析文件操作 [进阶篇_ 复习专用]_c_Dream-Y.ocean_InfoQ写作社区