C语言的文件操作【文件读取结束的判定和文件缓冲区】
目录
- 前言
- 一、文件读取结束的判定
- 1.1 feof()函数和ferror()函数简介
- 1.2 feof()函数和ferror()函数的使用
- 二、拷贝文件的C语言程序
- 三、文件缓冲区
- 3.1 什么是文件缓冲区
- 3.2 为什么要有文件缓冲区
- 3.3 如何证明
- 总结
前言
文件在读取结束,有两种原因,一个是遇到了文件末尾,另一个是读取的时候发生了错误,那我们如何得知是哪种结束原因,我们话不多说,正文如下:
一、文件读取结束的判定
其实,我们在打开一个流的时候,这个流有两个标记值:
- 是否遇到文件末尾;
- 是否发生错误。
那我们在文件读取结束后,是什么原因导致读取结束的呢?
- 遇到了文件末尾;
- 读取的时候发生了错误。
那我们如何得知是什么原因呢?
我们可以通过feof和ferror函数得知;
1.1 feof()函数和ferror()函数简介
feof、ferror 函数参数
两个函数的参数都是 文件指针,这里需要注意的是两个函数的返回值。
feof函数的返回值
如果没有到文件尾,返回0;到达文件尾,返回一个非零值。
ferror函数的返回值
无错误出现时返回0;有错误出现时,返回一个非零值。
被错误使⽤的 feof
牢记:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。
feof 的作⽤是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束。
1.2 feof()函数和ferror()函数的使用
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}char c = 0;while ((c = fgetc(pf)) != EOF) // 标准C I/O读取⽂件循环{putchar(c);}printf("\n");//判断是什么原因结束的if (ferror(pf))puts("I/O error when reading");else if (feof(pf))puts("End of file reached successfully");fclose(pf);pf = NULL;return 0;
}
如果读取顺利,会成功读出文件末尾:
二、拷贝文件的C语言程序
看到这里了,我相信,大家对C语言的文件操作有了一定的理解;
那我们用C语言来实现对一个文件拷贝到另一个文件:
我们写这个程序前,我们要注意:
我们首先一定是要用fopen打开两个文件,打开文件我们就要判断是否打开成功,我们在判断第二个文件是否打开成功的时候,如果打开失败,我们不仅要关闭第二个文件,还要关闭第一个文件,这时我们要注意的;
int main()
{FILE* pfin = fopen("test1.txt", "r"); //打开需要拷贝的文件if (pfin == NULL){perror("fopen:test1.txt:");return 1;}FILE* pfout = fopen("test2.txt", "w"); //拷贝的位置if (pfout == NULL){fclose(pfin);pfin = NULL;perror("fopen:test2.txt:");return 1;}int ch = 0;while ((ch = fgetc(pfin)) != EOF){fputc(ch, pfout);}fclose(pfin);pfin = NULL;fclose(pfout);pfout = NULL;return 0;
}
三、文件缓冲区
3.1 什么是文件缓冲区
ANSIC 标准采⽤“缓冲⽂件系统” 处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为程序中每⼀个正在使⽤的⽂件开辟⼀块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的⼤⼩根据C编译系统决定的。
结合此图理解:
3.2 为什么要有文件缓冲区
文件缓冲区(File Buffer)是操作系统为文件操作提供的一种机制,它位于用户程序和磁盘之间,主要有以下几个作用:
-
提高效率:
- 减少磁盘I/O操作:磁盘I/O操作通常比内存操作要慢得多。通过使用文件缓冲区,程序可以先将数据写入内存中的缓冲区,当缓冲区满了之后再一次性写入磁盘,这样可以减少磁盘I/O操作的次数,提高效率。
- 局部性原理:程序访问数据时往往具有空间局部性和时间局部性,即倾向于访问相邻或近期访问过的数据。文件缓冲区可以利用这一原理,预先加载数据到内存中,提高后续访问速度。
-
减少碎片化:
- 直接对磁盘进行频繁的小规模写操作会导致磁盘空间碎片化,影响磁盘性能。文件缓冲区可以减少这种碎片化,因为它允许小规模写操作先在内存中合并,再一次性写入磁盘。
-
同步与异步操作:
- 缓冲区允许操作系统在后台异步地将缓冲区中的数据写入磁盘,这样可以避免程序在等待磁盘写入时被阻塞,提高程序的响应性和吞吐量。
-
数据完整性:
- 在写操作时,如果直接写入磁盘,一旦发生错误或程序崩溃,可能导致数据不完整。使用缓冲区可以先在内存中完成写操作,确保数据的完整性,然后再统一写入磁盘。
-
格式转换:
- 文件缓冲区还可以用于数据格式的转换,例如在文本模式和二进制模式之间转换,或者处理不同操作系统和文件系统之间的差异。
-
错误处理:
- 缓冲区可以提供错误处理机制,例如在写入磁盘时检测到错误,可以回滚到缓冲区中的数据,而不是直接丢弃。
-
用户空间与内核空间的隔离:
- 缓冲区还可以作为用户空间和内核空间之间的缓冲,减少上下文切换的开销。
总之,文件缓冲区是一种提高文件操作效率、保证数据完整性、优化系统性能的重要机制。
3.3 如何证明
那,我们怎么才能知道,我们有文件缓冲区,我们提供下面的程序:
#include <stdio.h>
#include <windows.h>
//VS2019 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;
}
总结
这期我们主要讲了文件读取结束的判定,判定文件读取结束通常依赖于读取函数的返回值和 feof() 函数。在实际应用中,可能需要根据具体情况选择合适的方法或组合使用多种方法来确保程序的正确性和健壮性。下期见,加油!