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

深入解析文件操作(下)- 文件的(顺序/随机)读写,文件缓冲区,更新文件

目录

  • 一、文件的顺序读写( 顺序读写函数介绍)
    • 1.1 fputc
    • 1.2 fgetc
    • 1.3 feof和ferror
    • 1.4 fputs
    • 1.5 fgets
    • 1.6 fprintf
    • 1.7 fscanf
    • 1.8 fwrite
    • 5.9 fread
    • 5.10 对比一组函数
      • 5.10.1 sprintf
      • 5.10.2 sscanf
  • 二、文件的随机读写
    • 6.1 fseek
    • 6.2 ftell
    • 6.3 rewing
  • 三、文件缓冲区
    • 7.1 fflush
  • 四、更新文件
  • 五、总结:


一、文件的顺序读写( 顺序读写函数介绍)

在这里插入图片描述
最后的fread和fwrite是针对二进制文件的读和写
上图所说的适用于所有输入流一般指适用于标准输入流和其他输入流(如文件输入流);所有输出流一般指适用于标准输出流和其他输出流(如文件输出流)。


1.1 fputc

int fputc ( int character, FILE* stream );

功能:将参数character指定的字符写入到stream指向的输出流中,通常用于向文件或标准输出流写入字符,在写入字符之后,还会调整指示器,字符会被写入流内部位置指示器当前指向的位置,随后该指示器自动向前移动一个位置。

参数
character:被写入的字符。
stream:是一个FILE*类型的指针,指向了输出流(通常是文件流或stdout)

返回值

  • 成功时返回写入的字符(以int形式,也就是ASCII码)。
  • 失败时返回EOF(通常是-1),错误指示器会被设置,可通过ferror()检查具体错误。

代码演示

在这里插入图片描述
这里程序运行结束后,打开程序当前路径的data.txt文件,就发现abcd写入文件中了。

写入文件输出流:
实际上的运行过程是打开文件之后,data.txt就有个文件光标(文件指示器),写入a后,光标a就移到a之后的位置,以此类推。

写入标准输出流:
标准输出流的名字就是stdout(屏幕)
在这里插入图片描述
当然这里也可以根据自己需要在文件里写值,比如这里要将a-z 26个字母写到文件中
在这里插入图片描述

1.2 fgetc

int fgetc ( FILE* stream );

功能:从参数stream指向的流中读取一个字符,函数返回的是文件指示器当前指向的字符,读取这个字符之后,文件指示器自动前往到下一个字符。

参数
stream:FILE* 类型的文件指针,可以是stdin,也可以是其他输入流的指针。如果是stdin就从标准输入流读取数据(键盘)。如果是文件流指针,就从文件读取数据。

返回值

  • 成功时返回读取的字符(以int形式)
  • 若调用时流已处于文件末尾,函数返回EOF并设置流的文件结束指示器(feof)。
  • 若发生读取错误,函数返回EOF并设置流的错误指示器(ferror)。

代码演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3 feof和ferror

int feof(FILE* stream);
//检测stream指针指向的流是否遇到文件末尾int ferror(FILE* stream);
//检测stream指针指向的流是否发生读/写错误

如果在读取文件的过程中,遇到了文件末尾,文件读取就会结束。这时读取函数会在对应的流上设置一个文件结束的指示符,这个文件结束指示符可以通过feof函数检测到。如果feof函数检测到文件结束指示符已经被设置,则返回非0的值,如果没有设置则返回0.

如果在读/写文件的过程中,发生了读/写错误,文件读取就会结束。这时读/写函数会在对应的流上设置一个错误指示符,这个错误指示符可以通过ferror函数检测到。如果ferror函数检测到错误指示符已经被设置,则返回非0的值,如果没有设置则返回0

对应的应用场景如下:
在这里插入图片描述
前面六次循环正常从文件中一个字符一个字符的读取,第七次之后就遇到文件末尾了。
在这里插入图片描述
这里补充一下,以写的形式打开文件时,如果原文件内有内容,再次运行程序会把里面的内容全部清理掉,相当于打开了一个新的文件。

1.4 fputs

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

功能:将参数str指向的字符串写入参数stream指定的流中(不包括结尾的空字符\0),适用于文件流或标准输出流(stdout)。

参数
str:str是指针,指向了要写入的字符串(必须以\0结尾)
stream:是一个FILE *的指针,指向了要写入字符串的流

返回值

  • 成功时返回非负整数。
  • 失败时返回EOF(-1),同时会设置流的错误指示器,可以使用ferror()检查错误原因。

代码演示

在这里插入图片描述

1.5 fgets

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

功能:从stream指定输入流中读取字符串,至读取到换行符、文件末尾(EOF)或达到指定字符数,然后将读取到的字符串存储在str指向的空间中。

参数

  • str:是指向字符数组的指针,str指向的空间用于存储读取到的字符串。
  • num:最大读取字符数(包含结尾的\0,实际最多读取num-1个字符)
  • stream:输入流的文件指针(如文件流或stdin)

返回值

  • 成功时返回str指针
  • 若在尝试读取字符时遇到文件末尾,则设置文件结束指示器,并返回NULL,需通过feof()检测
  • 若发生读取错误,则设置流错误指示器,并返回NULL,通过ferror()检测

代码演示

在这里插入图片描述
在这里插入图片描述
注意这里的/0是函数自动添加的,不是从字符串中读取的

使用细节

  • 若读取到换行符(\n),会将其包含在字符串中(除非超出num-1限制),然后以\0结尾
  • 文件末尾无换行符时,字符串以\0结尾,不包含\n

1.6 fprintf

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

功能:fprintf 是将格式化数据写入指定文件流的函数,它与printf类似,但可以输出到任意输出流(如磁盘文件、标准输出、标准错误等),而不仅限于控制台(这里控制台就是标准输出)

参数

  • stream:指向FILE对象的指针,表示要写入的文件流(如stdout、文件指针等)
  • format:格式化字符串,包含要写入的文本和格式说明符(如%d、%s等)
  • . . .:可变参数列表,提供与格式字符串中说明符对应的数据

返回值

  • 成功时,返回写入的字符总数(非负值)
  • 失败时,先设置对应流的错误指示器,再返回负值,可以通过ferror()来检测

代码演示

在这里插入图片描述

1.7 fscanf

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

功能:fscanf是从指定文件流中读取格式化数据的函数,它类似于scanf,但可以指定输入源(如文件、标准输入等),而非仅限于控制台输入(标准输入)。适用于从文件解析结构化数据(如整数、浮点数、字符串等)。

参数

  • stream:指向FILE对象的指针,表示要读取的文件流(如stdin、文件指针等)
  • format:格式化字符串,定义如何解析输入数据(如%d、%f、%s等)
  • . . . :可变参数列表,提供存储数据的变量地址(需与格式字符串中的说明匹配)

返回值

  • 成功时(部分读取成功也算),函数返回成功填充到参数列表中的项数(几个占位符的数据被匹配上)。该值可能与预期项数一致,也可能因以下原因少于预期(甚至为零):
    • 格式和数据匹配失败
    • 读取发生错误:
    • 到达文件末尾(EOF)
  • 如果在成功读取任何数据之前发生:
    • 发生读取错误,会在对应流上设置错误指示符,则返回EOF。
    • 到达文件末尾,会在对应流上设置文件结束指示符,则返回EOF。

代码演示

在这里插入图片描述

前面的这些函数写到文件中的是文本信息,即是以ASCII码形式写进去的信息,得到的是文本文件,直接以记事本打开可以看懂
接下来的两函数是以二进制形式写文件的,得到的文件时二进制的文件

1.8 fwrite

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

功能:函数用于将数据块写入stream指向的文件流中,是以二进制的形式写入的。

参数

  • ptr:只想要写入的数据块的指针
  • size:要写入的每个数据项的大小(以字节为单位)
  • count:要写入的数据项的数量
  • stream:指向FILE类型结构体的指针,制定了要写入数据的文件流

返回值:返回实际写入的数据项数量。如果发生错误,则返回值可能小于count

使用注意事项

  • 需要包含<stdio.h>
  • 在使用fwrite()之前,需要确保文件已经以二进制可写方式打开。
  • fwrite()通常用于二进制数据的写入,如果写入文本数据。要谨慎处理换行符和编码等问题

代码演示

在这里插入图片描述
这里用二进制编辑器打开,上一篇介绍过打开方法
深入解析文件操作(上)- 二进制文件和文本文件,流的概念,文件的打开和关闭

5.9 fread

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

功能:函数用从stream指向的文件流中读取数据块,并将其存储到ptr指向的内存缓冲区中。

参数

  • ptr:指向内存区域的指针,用于存储从文件中读取的数据
  • size:要读取的每个数据块的大小(以字节为单位)
  • count:要读取的数据块的数量
  • stream:指向FILE类型结构体的指针,制定了要从中读取数据的文件流

返回值:返回实际读取的数据块的数量

使用注意事项

  • 需要包含<stdio.h>头文件
  • 在使用fread()之前,需要确保文件已经以二进制可读方式打开
  • ptr指向的内存区域必须足够大,以便存储指定数量和大小的数据块
  • 如果fread()成功读取了指定数量的数据块,则返回值等于count;如果读取数量少于count,则可能已经到达文件结尾或者发生了错误
  • 在二进制文件读取时,fread()是常用的函数,但对于文本文件读取,通常使用fgets()或fscanf()。

代码演示

在这里插入图片描述

5.10 对比一组函数

5.10.1 sprintf

int sprintf ( char* str,const char* format,... );

功能:将格式化数据写入字符数组(字符串)。它类似于printf,但输出目标不是控制台或文件,而是用户指定的内存缓冲区。常用于动态生成字符串、拼接数据或转换数据格式。简而言之就是将格式化的数据转换成一个字符串。

参数

  • str:指向字符数组的指针,用于存储生成的字符串(需确保足够大以防止溢出)
  • format:格式化字符串,定义输出格式(如%d、%f、%s等)
  • . . . :可变参数列表,提供与格式字符串中说明符对应的数据

返回值

  • 成功时:返回写入buffer的字符数(不包含结尾的空字符\0)
  • 失败时:返回负值

5.10.2 sscanf

int sscanf ( const char* str,const char* format, ... );

功能:从字符串中读取格式化数据。它与scanf类似,但输入源是内存中的字符串而非控制台或文件。常用于解析字符串中的结构化数据(如提取数字、分割文本等)。

参数

  • str:要解析的源字符串(输入数据来源)
  • format:格式化字符串,定义如何解析数据(如%d、%f、%s等)
  • . . . :可变参数列表,提供存储数据的变量地址(需与格式字符串中的说明符匹配)

返回值

  • 成功时:返回成功解析并赋值的参数数量(非负值)
  • 失败或未匹配任何数据:若输入结束或解析失败,返回EOF(通常是-1)

两函数代码演示

在这里插入图片描述

总结:
scanf:针对标准输入(stdin)的格式化输入函数
printf:针对标准输出(stdout)的格式化输出函数
fscanf:针对所有输入流(可以是文件流,也可以是stdin)的格式化输入函数
fprintf:针对所有输出流(可以是文件流,也可以是stdout)的格式化输出函数
sprintf:将可视化的数据转换成字符串
sscanf:从字符串中提取格式化的数据


以上都是文件的顺序读写,下面的内容是文件的随机读写

二、文件的随机读写

6.1 fseek

根据文件指针的位置和偏移量来定位文件指针(文件内容的光标)

int fseek ( FILE* stream,long int offset,int origin );
//                       偏移量        起始位置(有取值范围)

origin的三个取值
在这里插入图片描述

补充:fopen打开文件时,光标默认在最开始的位置
在这里插入图片描述

忘记函数参数的话按逗号就会有提示

在这里插入图片描述
这里读完a光标的位置就会来到这里

比如这里第一次读a,下一次读g
在这里插入图片描述
注意:向左偏移为负数,向右偏移为正数

6.2 ftell

返回文件相对于起始位置的偏移量

long int ftell ( FILE* stream );

6.3 rewing

让文件指针的位置回到文件的起始位置

void rewind ( FILE* stream );

演示代码

在这里插入图片描述

三、文件缓冲区

ASCI C标准采用“缓冲文件系统”处理数据文件的,所谓缓冲文件系统是指系统自动的在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存中向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区地大小根据C编译系统决定的。
在这里插入图片描述
本质上文件缓冲区的作用是用来提升效率的,写数据到文件的过程会调用操作系统的接口,操作系统是来管理电脑中的硬件的,如果没写一个数据调用一次操作系统,操作系统就会忙的起飞,而操作系统上跑了很多的程序,打开任务管理器就可以看到,如果只为一个程序耗时这么久,效率就会很低,文件缓冲区就是待缓冲区充满的期间,操作系统可以为其他程序做服务。

缓冲又可以分为:完全缓冲,行缓冲(\n),无缓冲
完全缓冲即上述内容,行缓冲则是遇到\n进行一次缓冲操作,无缓冲为无缓冲操作,直接将数据写入硬盘。

下面的函数就可以随时随地的将缓冲区中的数据写入硬盘

7.1 fflush

int fflush ( FILE* stream );

功能:强制刷新参数stream指定流的缓冲区,确保数据写入底层设备

  • 输出流:将缓冲区中为写入的数据立即写入文件
  • 输入流:行为由具体实现决定,非C语言标准行为(可能清空输入缓冲区)
  • 参数为NULL时:刷新所有打开的输出流

参数
stream:指向文件流的指针(如stdout、文件指针)
返回值:成功返回0,失败返回EOF
注意事项

  1. 仅对输出流更新流(最后一次操作为输出)有明确刷新行为
  2. 输入流的刷新行为不可移植(如清空输入缓冲区是非标准特性)
  3. 程序正常终止(exit)或调用fclose时会自动刷新,但程序崩溃时缓冲区数据可能丢失

在这里插入图片描述
这里可以得出一个结论:
因为由缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。
如果不做,可能导致读写文件的问题

四、更新文件

更新文件有三种方式:
在这里插入图片描述
关键要点

  1. 在写完文件后,要继续读文件的时候,在读取之前一定要使用fflush()刷新文件缓冲区,或者使用fseek(),rewind()重新定位文件指示器的位置
  2. 在读完文件后,需要继续写文件之前,使用fseek(),rewind()重新定义文件指示器的位置

代码演示

在这里插入图片描述

五、总结:

以上就是文件操作下的全部内容了,这一周是过的真难受,莫名就陷入摆烂了,不过还好调整过来了,继续努力!

http://www.lryc.cn/news/598645.html

相关文章:

  • 模块化商城的快速部署之道:ZKmall开源商城如何让电商功能即插即用
  • 前端安全问题怎么解决
  • 常用设计模式系列(十一)—外观模式
  • C++ 中打开文件的多种方式及相关流类
  • 三维手眼标定
  • Windows下使用UIAutomation技术遍历桌面窗口和指定窗口内容的AutomationWalker.exe的C#源代码
  • Java中的静态变量是在“堆“还是“方法区“?
  • 视频模型国产PK国外?
  • Leetcode—1035. 不相交的线【中等】
  • TDengine 转化类函数 CAST 用户手册
  • Windows 11下纯软件模拟虚拟机的设备模拟与虚拟化(仅终端和网络)
  • C++性能优化实战‘从毫秒到微秒的底层突围‘
  • Windows 10 停服:个人与企业的 “系统选择题”
  • MNIST 手写数字识别模型分析
  • 《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——4. 前后端联动:打通QML与C++的任督二脉
  • LAYOUT 什么时候需要等长布线?
  • 【牛客刷题】和零在一起
  • 【Linux】Linux了解与基本指令(1)
  • 数据库期中复习
  • SkyWalking异步采集spring gateway日志
  • postgresql执行创建和删除时遇到的问题
  • AWS云S3+Glue+EMRonEC2+ReadShift
  • ThinkPHP8集成RabbitMQ的完整案例实现
  • 使用 Strands Agents 开发并部署生产级架构通用型个人助手
  • 【论文阅读】基于EEG的冥想状态数据挖掘研究(2025)
  • 深入探索Amazon SQS:构建弹性微服务与无服务器应用的秘密武器
  • Nodejs:从“模块未找到”到“大师之路”, 项目初始化与依赖安全完全指南
  • JimuReport 积木报表 v2.1.1 版本发布,免费开源的报表和大屏
  • 主流摄像头协议及其开源情况,GB/T 28181协议介绍
  • Word2Vec模型训练全流程解析:从数据预处理到实体识别应用