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

C文件操作2

五、文件的随机读写

这些函数都需要包含头文件 #include<stdio.h>

5.1 fseek

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

重新定位流位置指示器

int fseek ( FILE * stream, long int offset, int origin );

  • 将与流关联的位置指示器设置到一个新的位置。
  • 对于以二进制模式打开的流,新位置是通过将偏移量(offset)加到由起始点(origin)指定的参考位置来确定的。
  • 对于以文本模式打开的流,偏移量必须为零或者是之前调用 ftell 函数所返回的值,并且起始点必须是 SEEK_SET
  • 如果操作成功,该函数返回零。否则,它返回非零值。
  • 如果发生读或写错误,错误指示器(`ferror`)将被设置。 

fseek函数的起始点(参考点)有三种类型:

int main()
{FILE* pf = fopen("test.txt","r");if(pf == NULL){perror("fopen");}else{int ch = fgetc(pf);printf("%c\n",ch);//ach = fgetc(pf);printf("%c\n",ch);//bch = fgetc(pf);printf("%c\n",ch);//c//如果继续往下读,必然是d//但是我们调整一下,去读取:bfseek(pf,-2,SEEK_CUR);//fseek(pf,1,SEEK_SET);ch = fgetc(pf);printf("%c\n",ch);//bfclose(pf);pf = NULL;}return 0;
}

5.2 ftell

返回文件指针相对于起始位置的偏移量(获取流中的当前位置)

long int ftell ( FILE * stream );

  • 返回流的位置指示器的当前值。
  • 对于二进制流
  • 这是从文件开头算起的字节数。
  • 对于文本流
  • 这个数值可能没有实际意义,但仍然可以使用 `fseek` 函数将位置恢复到相同的位置(如果有使用 `ungetc` 函数放回但尚未读取的字符,这种情况下行为是未定义的)。 
  • 操作成功时,将返回位置指示器的当前值。
  • 操作失败时,将返回 -1L,并将 `errno` 设置为一个系统特定的正值。 
int main()
{FILE* pf = fopen("test.txt","r");if(pf == NULL){perror("fopen");}else{int ch = fgetc(pf);printf("%c\n",ch);//ach = fgetc(pf);printf("%c\n",ch);//bch = fgetc(pf);printf("%c\n",ch);//c//如果继续往下读,必然是d//但是我们调整一下,去读取:bfseek(pf,-2,SEEK_CUR);//fseek(pf,1,SEEK_SET);ch = fgetc(pf);printf("%c\n",ch);//bprintf("%c\n",ftell(pf));//2fclose(pf);pf = NULL;}return 0;
}

5.3 rewind

让文件指针的位置回到文件的起始位置(将流的位置设置到文件开头)

void rewind ( FILE * stream );

int main()
{FILE* pf = fopen("test.txt","r");if(pf == NULL){perror("fopen");}else{int ch = fgetc(pf);printf("%c\n",ch);//ach = fgetc(pf);printf("%c\n",ch);//bch = fgetc(pf);printf("%c\n",ch);//c//如果继续往下读,必然是d//但是我们调整一下,去读取:bfseek(pf,-2,SEEK_CUR);//fseek(pf,1,SEEK_SET);ch = fgetc(pf);printf("%c\n",ch);//bprintf("%c\n",ftell(pf));//2rewind(pf);ch = fgetc(pf);printf("%c\n",ch);//afclose(pf);pf = NULL;}return 0;
}

六、文件文本和二进制文本

根据数据的组织形式,数据文件被称为文本文件或者⼆进制文件

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

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换,以ASCII字符的形式存储的文件就是文本文件

⼀个数据在文件中是怎么存储的呢? 字符⼀律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用⼆进制形式存储。如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符⼀个字节),而⼆进制形式输出,则在磁盘上只占4个字节。

以ASCII形式存储:字符

int main()
{int a = 10000;FILE* pf = fopen("test.txt","w");fwrite(&a,4,1,pf);//二进制的形式写到文件中fclose(pf);pf = NULL;return 0;
}

我们将 test.txt 文件在VS中打开,会发现它是一串十六进制数字10 27 00 00

此时的存储方式是二进制形式存储,而为了方便表示,一般会转化为十六进制形式:

七、文件读取结束的判定

需要包含头文件 #include <stdio.h>

7.1 被错误使用的 feof

int feof ( FILE * stream );

如果与该流相关联的文件结束指示器已设置,则返回一个非零值。 否则,返回零。

牢记:在文件读取过程中,不能用feof函数的返回值直接来判断文件的是否结束。(文件结束标志 ---- EOF[-1])

feof 的作用是:当文件读取结束的时候,判断读取结束的原因是否是:遇到文件尾结束。(检查文件结束指示器)

1.文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )

例如:

• fgetc 判断是否为 EOF

• fgets 判断返回值是否为 NULL 

2.二进制文件的读取结束判断,判断返回值是否小于实际要读的个数

例如:

• fread判断返回值是否小于实际要读的个数。

7.2  ferror

int ferror ( FILE * stream );

如果与该流相关联的错误指示器已设置,则返回一个非零值。否则,返回零值。

ferror 的作用是:当文件读取结束的时候,判断是读取结束的原因是否是:文件操作中发生了错误。(检查错误指示器)

文本文件例子:

//!pf 通常用于检查文件指针 pf 是否为 NULL,即判断文件是否成功打开或有效。
//! 是逻辑非运算符,用于对指针进行逻辑取反。
//当 pf 为 NULL 时,!pf 的值为 1(真),表示文件打开失败。
//当 pf 有效(非 NULL)时,!fp 的值为 0(假),表示文件已成功打开。
int main()
{int c;// 注意:int,⾮char,要求处理EOFFLIE* pf = fopen("test.txt","r");if(!pf) // 等价于 if (pf == NULL){perror("fopen");return 1;}//fgetc 当读取失败的时候或者遇到⽂件结束的时候,都会返回EOFwhile((c=fgetc(pf)) != EOF)// 标准C I/O读取⽂件循环{putchar(c);}//判断是什么原因结束的if(ferror(pf)) //返回真,就说明是文件在读取过程出错而结束printf("I/O error when reading");else if(feof(pf)) //返回真,就说明是文件正常读取遇到结束标志而结束printf("End of file reached successfully");fclose(pf);pf = NULL;return 0;
}

二进制文本例子:

enum {SIZE = 5};
int main()
{doublle a[SIZE] = {1,2,3,4,5};FILE* pf = fopen("test.txt","wb");// 必须⽤⼆进制模式fwrite(a,sizeof *a,SIZE,pf);// 写 double 的数组fclose(pf);double b[SIZE] = {0};pf = fopen("test.txt","rb");size_t ret = fread(b,sizeof *b,SIZE,pf);// 读 double 的数组if(ret == SIZE){int n = 0printf("Array read successfully, contents");for(n = 0;n < SIZE; n++){printf("%f ",b[n]);}}printf("\n");else{if(feof(pf))printf("Error reading text1.txt: unexpected end of file\n");else if(ferror(pf))printf("Error reading text1.txt");}fclose(pf);pf = NULL;return 0;
}

八、文件缓冲区

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

#include <stdio.h>
#include <windows.h>
//VS2022 WIN11环境测试 
int main()
{FILE*pf = fopen("test.txt", "w");fputs("abcdef", pf);//先将代码放在输出缓冲区 printf("睡眠10秒-已经写数据了,打开test.txt⽂件,发现⽂件没有内容\n");Sleep(10000);printf("刷新缓冲区\n");fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到⽂件(磁盘) //注:fflush 在⾼版本的VS上不能使⽤了 printf("再睡眠10秒-此时,再次打开test.txt⽂件,⽂件有内容了\n");Sleep(10000);fclose(pf);//注:fclose在关闭⽂件的时候,也会刷新缓冲区 pf = NULL;return 0;
}

fflush —— 刷新缓冲区       fclose —— 关闭文件的时候也会刷新缓冲区

这里可以得出一个结论:

因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。如果不做,可能导致读写文件的问题。

http://www.xdnf.cn/news/12358.html

相关文章:

  • python打卡训练营打卡记录day46
  • 在aarch64平台编译写入传统xls格式文件开源库xlslib的步骤
  • 《影像引导下骨盆创伤手术的术前骨折复位规划:基于学习的综合流程》|文献速递-深度学习医疗AI最新文献
  • [论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
  • 密码学基础——SM4算法
  • 飞云智能波段主图+多空短线决策副图指标,组合操盘技术图文解说
  • 网页端 js 读取发票里的二维码信息(图片和PDF格式)
  • 机器学习算法时间复杂度解析:为什么它如此重要?
  • 国内环境修改 flutter.bat 来设置 flutter 的网络环境
  • Java项目中常用的中间件及其高频问题避坑
  • 第7篇:中间件全链路监控与 SQL 性能分析实践
  • 区块链电子发票试点政策DID数据(2016-2025)
  • 绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
  • 【001】frida API分类 总览
  • Spring Boot 定时任务的使用
  • 从webrtc到janus简介
  • vue-21 (使用 Vuex 模块和异步操作构建复杂应用)
  • 单元测试与QTestLib框架使用
  • 字符串 金额转换
  • 简约商务年终工作总结报告PPT模版分享
  • Qt(part1)Qpushbutton,信号与槽,对象树,自定义信号与槽,lamda表达式。
  • LRU 和 DiskLRU实现相册缓存器
  • coze平台创建智能体,关于智能体后端接入的问题
  • Typeerror: cannot read properties of undefined (reading ‘XXX‘)
  • 【Linux】(1)—进程概念-④fork、僵尸进程、孤儿进程
  • 【Linux】(1)—进程概念-⑤进程调度
  • 如何把本地服务器变成公网服务器?内网ip网址转换到外网连接访问
  • 国芯思辰| AD7894的优质替代方案:SC1424模数转换器在分布式控制系统中的应用优势
  • I2C通信讲解
  • Git的由来与应用详解:从Linux内核到现代开发的革命性工具