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

C语言:文件操作(2)

文件的顺序读写

关于对文件的读和写操作,一共有四组函数,我们先说写文件,再说读的文件的函数。

fputc和fgetc

fputc

fputc是输出单个字符到输出流中,使用包含两个参数,ch是要写入文件中的字符,stream是输出流。在"w"模式下使用。

比如说我们要写一个字符到text.txt文件中。


写入成功。
如果要把字符’a’到’z’都写入该文件中,我们可以这样写:


就写进去了。

fgetc

我们想从text.txt文件中读取单个字符出来,就可以用fgetc函数。该函数在"r"模式下使用。
fgetc是用来从输入流中读取单个字符的函数,包含一个参数stream,是读取字符的来源。该函数返回的是该字符的ascll值 ,为int类型。当遇到错误指示器或者读到文件末尾时,返回EOF。

我们从text.txt文件中读取一个字符:

当我们读取到一个字符时,文件指针pf就会自动指向下一个字符:

我们如果想把文件读完可以这样写:

当遇到文件末尾时返回EOF,循环停止。

fputs和fgets

fputs

fputs是用来输出一个字符串到输出流中的函数,包含两个参数,str是指向要写入的字符串的指针,stream是输出流。在"w"模式侠下是使用。我们想写"hello world"到文件date.txt中:

如果再写入一个字符串"wonderful"呢?


我们发现第二个字符串写入该文件时没有换行,直接在第一个字符串后面写入了。当我们想换行的时候,可以在第一个字符串后面手动添加\n:


这就是fputs的使用。

fgets

fgets就是从输入流中读取字符串的函数,包含三个参数:str,count,stream
。str就是用来放读取出来的字符串的字符数组的,count是读取出来字符的长度,因为会在读取出来的字符串后面主动添加’\0’,所以最多可以读取出count-1个字符,stream就是读取字符串来源的输入流。如果读到文件末尾或者遇到’\0’就自动停止读取。该函数在"r"模式下使用。




遇到换行符停止读取,所以只读了"hello world\n"。这时文件指针pf指向了字符’w’:

第二行字符串读取到文件末尾后停止读取。

fprintf和fscanf

fprintf

fprintf是输出格式化的数据到输出流中,在"w"模式下使用。可以对比printf的用法。


和printf相比,在前面多了一个参数stream输出流。
比如我们要写数据到文件date.txt中:


这样就可以写入数据到文件中了,结构体也可以写入:

fscanf

fscanf是从输入流中读取格式化的数据,在"r"模式下使用,使用也可以对照scanf。


与scanf相比前面多了个参数stream输入流。
比如说我们要从文件date.txt中读取格式化的数据:

fwrite和fread

fwrite

fwrite是写入格式化的数据到文件输出流,该函数在"wb"模式下使用。包含四个参数:buffer,指向要写入的数据的首对象。size,每个对象的大小,count,要写入的对象的个数。stream,文件输出流。


这样就可以把arr数组中的五个元素以二进制形式写进文件test.txt中了。
我们以记事本(文本文件的形式)打开该文件,是看不懂的。

但我们可以在程序中以二进制形式打开该文件:


这样就能看懂了,存了1,2,3,4,5这五个元素。

fread

fread是从文件输入流中读取数据块,该函数在"rb"模式下使用,包含参数跟fwrite一模一样,但参数意义变了,buffer是用来接收从文件中读取到的数据块的,size是数据块的大小,count是读取数据块的个数,stream是文件输入流。

比如我们要从文件test.txt中读取数据块:


读取成功。

文件的随机读写

当一个文件中存放abcdef时,我们想读完字符a后,下一个字符读b该怎么做?
我们知道,fgetc函数从文件中读取一个字符后,指向该文件的指针就会指向下一个字符。

当fgetc读完文件中的字符a时,指针pf就会偏移指向下一个字符b,如何跳过前面的字符读取到d?

fseek

介绍一个函数fseek,它是用来移动文件指针,改变下一次读取文件的位置的。包含三个参数,stream是打开的文件流,offset是偏移量,origin是基准位置,可以是三个参数:SEEK_SET,SEEK_CUR,SEEKEND。SEEK_SET是文件起始位置,SEEK_CUR是文件指针当前指向的位置,SEEK_END是文件末尾。offset这个偏移量就是相对于参数origin来说的。

比如说我读完字符a想直接读字符d,那我可以这样写:


通过fseek来偏移指针当前文件指针指向的位置,再通过fgetc读取文件指针指向字符的ascll值,就可以直接读取到字符d。
这里我们给origin传的是SEEK_CUR,是当前文件指针指向的位置。读取了字符a后当前文件指针指向的位置后移,指向了字符b,把文件指针往后偏移2个字节,该文件指针指向的就变成了字符d,通过fgetc读取到的字符就变成了d。
除了SEEK_CUR,我们还可以传另外两个参数,都可以达到同样的效果。

fseek(pf,3,SEEK_SET);//传的是文件起始位置,向后偏移3个字节,文件指针指向d
fseek(pf,-2,SEEK_END);//传的是文件末尾,向前偏移两个字节,文件指针指向d

这就是fseek函数的使用。

ftell

如果我们想知道目前文件指针相对于文件开头的偏移量,我们可以用ftell函数。传过去当前的文件指针sream,返回偏移量。注意返回值类型是long int。


读取字符d后,文件指针指向了字符e,相对于文件开头,a到e偏移了4个字节。

rewind

如果我们想让文件指针指向的位置回到文件开头,就可以使用rewind函数。
使用很简单,就把当前文件指针传入就行了。


使用rewind函数后,用ftell函数可以看出,当前文件指针相对于文件开头的偏移量为0,说明rewind函数成功地让文件指针指向的位置回到了文件开头。

文件读取结束的判定

在文件读取的时候,读取结束有两种可能:遇到错误指示器;读到文件末尾。我们不知道文件长度是多少,那如何判断文件是否读取结束呢?

fgetc,fgets,fread读取结束的判定

判断文件是否读取结束的办法是根据函数返回值来看的。

fgetc

fgetc在读取文件的时候,如果读取失败则会设置一个错误指示器,然后返回EOF(end of file)。如果读取到文件末尾也会返回EOF。所以判断fgetc返回值是不是EOF就可以判断文件读取是否结束。

fgets

fgets在读取文件的时候,如果读取失败则会设置一个错误指示器,然后返回NULL。如果读取到文件末尾也会返回NULL。所以判断fgetc返回值是不是EOF就可以判断文件读取是否结束。

fread

fread读取二进制文件返回的是读取成功的数据块的个数,比如我们要读取的文件中有8个数据块,第一次我读取了5个数据块,还剩3个数据块没读取。第二次我读取5个数据块,成功读取了3个数据块。当我们成功读取的数据块个数少于我们要读取的数据块的个数时,说明文件读取结束。

判断文件读取结束的原因

feof和ferror

feof是用来判断文件读取结束是不是因为读到文件末尾了,不是则返回NULL。
ferror是用来判断文件读取结束是不是因为遇到错误指示器了,不是则返回NULL。
比如说我们要判断一个文件读取结束的原因:


说明文件读取结束了,是读取到文件末尾才结束的。

文件缓冲区

ANSl C标准采用“缓冲文件系统”处理数据文件,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区,充满缓冲区后再从缓冲区逐个地将数据送到程序数据区,缓冲区的大小根据C编译系统决定。

http://www.cnnetsun.cn/news/2684550.html

相关文章:

  • LabVIEW 2021生成EXE后报表报错7?手把手教你添加NIReport.llb和LVClass文件
  • 监控画面总有雪花噪点?深入拆解海思/安霸芯片里的3D降噪技术到底是怎么工作的
  • LaMa图像修复模型训练避坑指南:从动态掩膜生成到损失函数调参
  • 从Cadence Tempus到Synopsys PT:手把手教你搞定两大神器下的check_timing检查
  • Flutter集成OpenAI API:构建流式AI对话应用的全栈实践
  • BK7231U SPI烧录避坑指南:从玄学Python脚本到稳定一键操作的进化之路
  • 超越基础教程:手把手教你用Niagara模块组合,打造更真实的游戏场景烟雾(含SubImageIndex随机技巧)
  • 避坑指南:动手仿真增量调制(∆M)过载与量化噪声(附MATLAB/Python代码)
  • 告别塑料玩具:聊聊工业级DLP光机在3D打印与扫描中如何‘扛’住产线环境
  • 基于GPT与Pytest的API自动化测试生成实践
  • Shell脚本进阶:用mapfile的-C回调函数,实现大文件读取的实时进度条
  • Arduino Uno + THB6128驱动板:从光耦限流计算到完整接线,搞定两相四线步进电机的保姆级避坑教程
  • 医疗AI智能体:从架构设计到临床落地的核心路径
  • 从晶体对称性到代码实现:高阶力常数插值中那些被你忽略的‘约束’到底怎么用?
  • 别再只聊NeRF了!3DGS实战:用Colmap+3D Gaussian Splatting快速重建你的房间(附完整代码)
  • 告别nRF Mesh APP:用ESP32自制BLE Mesh配网器,深入理解Provisioner底层事件与回调
  • 别再死记硬背了!用Input.GetAxis搞定Unity角色移动与旋转,附完整代码避坑
  • 倍福CX5130控制松下伺服:EtherCAT组网与轴参数调试避坑全记录
  • 别再手动调轮廓线了!分享一个我优化过的UE4高亮材质,直接拖进项目就能用
  • 别再乱编译OpenSSL了!CentOS 8/RHEL 8用户必须知道的系统库兼容性‘潜规则’
  • 别再傻傻分不清了!用FFmpeg实战演示RTMP直播推流与HLS点播切片(附完整命令)
  • 告别玄学!Python脚本全自动搞定BK7231U的SPI烧录(附完整代码)
  • 保姆级教程:在Mac M1/M2上用QEMU 8.2跑起Windows 10 ARM64(附驱动和避坑指南)
  • 别再手动拖拽了!用Resources.Load在Unity里动态换UI图片(附完整C#脚本)
  • 避开WinForm卡死!用MQTTnet做C#物联网应用时,异步和事件处理到底该怎么写?
  • 告别Log混乱!用CAPL的setLogFileName函数实现自动化测试日志的精准归档
  • DeepSeek LeetCode 2876. 有向图访问计数 C语言实现
  • d3dx9_43.dll 丢失报错原因分析及三种标准修复方法
  • 用Arduino和MLX90614做个非接触测温仪,5分钟搞定硬件连接与代码调试
  • 自动化始于心智:从任务复制到思维系统的认知重构