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

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语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。如果不做,可能导致读写文件的问题。

相关文章:

  • error: subprocess-exited-with-error【已解决】
  • SCAU数值计算OJ
  • 2.1 Windows编译环境介绍
  • 《UE5_C++多人TPS完整教程》学习笔记37 ——《P38 变量复制(Variable Replication)》
  • WinCC学习系列-变量模拟器(WinCC TAG Simulator )
  • MajicTryOn(基于wanvideo的虚拟试穿项目)
  • @Minikube 部署与配置
  • 使用 Python 构建并调用 ComfyUI 图像生成 API:完整实战指南
  • 【大厂机试题解法笔记】观看文艺演出问题
  • 使用扩散模型解决Talking Head生成中的头像抖动问题
  • 毫米波雷达基础理论(3D+4D)
  • 20250606-C#知识:匿名函数、Lambda表达式与闭包
  • C#中datagridview单元格value为{}大括号
  • Compose基本介绍
  • 8.1_排序的基本概念
  • 【C++】24. 哈希表的实现
  • Day46
  • 消息队列高级特性与原理:解锁分布式系统的底层逻辑
  • 【信息系统项目管理师-论文真题】2025上半年(第一批)论文详解(包括解题思路和写作要点)
  • 【大模型LLM学习】Flash-Attention的学习记录
  • 失眠先生 wordpress/南宁百度seo排名价格
  • 如何投诉网站制作公司/网站建设选亿企网络
  • 供求信息网站建设报价/东莞网络推广
  • 保险做的好的网站有哪些/今日重大新闻头条十条
  • 网站建设需求计划书/百度首页清爽版
  • 来宾建设工程造价网站/外贸seo推广公司