最近写项目的时候碰到 feof 多读一次数据的坑。写个文章记录一下。
先来看一下feof()的定义
feof()声明
#include <stdio.h>
int feof( FILE *stream );
描述
feof()是检测给定流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回 0
feof的经典错误
很多人在用 feof 的时候会像下面这样写,结果就是无论文件是否有内容,都会输出 “The file is not empty” ,要想解决这个问题,就需要来看一下 feof() 的原理
#include<stdio.h>
int main(void)
{
FILE* fp = fopen("open.txt", "r");
if (feof(fp))
{
printf("empty file\n");
}
else
{
printf("The file is not empty\n");
}
return 0;
}
feof() 的原理
feof()函数,并不是通过读取到文件的EOF来判断这个文件是否为空。
对feof()来说,它的工作原理是,站在光标所在位置,向后看看还有没有字符。如果有,返回0;如果没有,返回非0。它并不会读取相关信息,只是查看光标后是否还有内容。
直接使用时的错误分析:
对于一个空文件来说,当程序打开它的时候,它的光标会停在文件的开头,但是由于文件里什么内容都没有存(但是EOF是存在的),即整个文件就存贮了一个EOF。当程序打开文件,并直接调用feof()时,这个函数就会站在光标的位置向后看,结果就看见了EOF,然后就返回0。
解决方法
因为读到文件末尾时feof还不能为真,需要再读一下才能为真。所以循环时可以在循环外面先读一次,然后进入循环再对前面读到的内容做处理,然后再往下读,再进入下次循环。这样就是每次循环处理上次循环读到的数据了。这样就解决了到文件末尾会多处理一次数据的问题。
//第一种
while(!feof(fp)){
printf("%s\n",buf); //处理上次循环读到的数据
fgets(buf, 100, fp); //本次循环读数据
}
//第二种
while(1){
fgets(buf,100,fp); //读取数据
if(feof(fp)){//到末尾了但是读之前这里返回假,执行printf,再循环一次,又经历了fgets后这里就为真了,直接退出,不再执行printf
break;
}
printf("%s\n",buf); //处理读到的数据
}