feof()判断文件结束的问题

我在编写学生成绩管理系统时用到了写文件和读文件,发现读文件总会显示出乱码,调试发现是因为用feof()做判断,在读文件最后时fread()多读取了一次。我一开始的解决办法是每次读取完文件,都把最后一个节点(每一行数据都读取放到链表的节点里)free掉。但这种方法明显不是那么好。

feof(fp)用来测试fp所指向的文件当前状态是否为“文件结束”。如果文件结束,则返回1,否则返回0。适合于二进制文件和文本文件。
但是,在实际使用feof时却发生了问题:文件实际已经结束时feof还要再判断一次才返回1
测试代码如下:

 1 #include <stdio.h>
 2 int main()
 3 {
 4     char ch = 0;
 5     int i = 0;
 6     FILE* fp;
 7     // 建立空文件
 8     fp = fopen("Info.txt", "w");
 9     if(NULL == fp)
10     {
11         printf("Cannot open file!\n");
12         return 0;
13     }
14     fclose(fp);
15     // 读取空文件
16     fp = fopen("Info.txt", "r");
17     if(NULL == fp)
18     {
19         printf("Cannot open file!\n");
20         return 0;
21     }
22     while(!feof(fp))
23     {
24         ch = fgetc(fp);
25         i++;
26     }
27     fclose(fp);
28     printf("fread times: %d\n"
29             "note: %c\n", i, ch);
30     return 0;
31 }

得到i为1,ch为空,说明feof()确实在文件为空状态时判断有误。

上网搜索有人说先读再判断就不会有问题了,但试了一下还是不行。对此,C FAQ-12.3的解释是“在C语言中,只有输入例程试图读并失败以后才能得到文件结束符。...fgets()在遇到文件结束符的时候返回NULL。实际上,在任何情况下,都完全没必要使用feof()。”

把while(!feof(fp)){}换成while(!fgets(str, 0, fp)){}确实能保证判断正确。但是,如果我在函数体里面还有其他读操作如fread()的话则会出现影响。所以,最好的解决办法是利用fseek()和ftell()配合来判断文件指针位置:

1 fseek(fp, 0L, SEEK_END);//文件指针置于结尾
2 len1 = ftell(fp);//获取结尾指针值
3 fseek(fp, 0L, SEEK_SET);//文件指针至于开头
4 len2 = ftell(fp);//获取开头指针值
5 while(len2 != len1)//循环判断
6 {
7     //do something
8     len2 = ftell(fp);
9 }

结果正确,无副作用。

其实还有另一种解决办法,就是每次写文件时在开头写入节点数,这样下次读文件时就知道要读取多少数据了。

ChinaUnix上也有一篇帖子对于这个问题讨论得很详细,但是提供的方法不适合我当时的情况:http://bbs.chinaunix.net/thread-957347-1-1.html

 

原文地址:https://www.cnblogs.com/jacobchen/p/2481267.html