feof多读一次问题分析

来源:互联网 发布:哗啦啦餐饮软件好用吗 编辑:程序博客网 时间:2024/06/06 09:30
在读完文件的最后一个字符后,fp->flag仍然没有被置为_IOEOF,因而feof()仍然没有探测到文件结尾。直到再次调用fgetc()执行读操作,feof()才能探测到文件结尾。这样就多执行了一次。对于feof()这个函数, 它是先读再判断是否到文件尾, 也就是说在它之前一定要读一次才能做出判断。

而我们经常这样把它使用在循环中:

int c;
while(!feof(fp))
{
  c = fgetc(fp);
  printf("%x\n",c);
}
 

它是先判断==>再读(可能这时就是文件尾了, 读不出东西了)
所以正确的代码应该是

int c;
c = fgetc(fp);//先读一次  
while(!feof(fp))
{
  printf("%x\n",c);
  c = fgetc(fp);  
}  

看出上面两段代码的区别了吧!!!
 

第二种方法就是:(不使用feof,换种方法。)
1、把文件内部指针移动到文件尾部。
fseek(fp,0,2);
2、用一个整形变量记录这个文件尾部的位置
wjcd = ftell(fp);
3、把文件内部指针移到到文件头部;
fseek(fp,0,0);
4、这样就可以了
while(wjcd == ftell(fp))

注:
1)   欲将读写位置移动到文件开头时:fseek(FILE   *stream,0,SEEK_SET);
2)   欲将读写位置移动到文件尾时:fseek(FILE   *stream,0,SEEK_END);

参数SEEK_SET是从距文件开头offset位移量为新的读写位置;SEEK_CUR是以目前的读写位置往后增加offset个位移量;SEEK_END将读写位置指向文件尾后再增加offset个位移量。当whence值为SEEK_CUR或SEEK_END时,参数offset允许负值的出现。



当feof(FILE *)读到EOF标志并不认为文件结束了,依旧返回0,直到读到EOF的下一个字符才返回1,这时才认为是文件结束。
因此若以while(!feof(fp))为循环条件的时候,要将一个文件(fp)完全复制到另一个文件(fp1),需要加上判断if(ch!=-1),如下:

while(!feof(in))
{
  ch=fgetc(in);
  if(ch!=-1)
  fputc(ch,out);

}
或者:
while(true)
{
   ch=fgetc(in);
   if(feof(in))
      break;
   putchar(ch);
   fputc(ch,out);
}


检测流上的文件结束符
The function feof() tests the end-of-file indicator for the stream
pointed to by stream, returning non-zero if it is set. The end-of-file
indicator can only be cleared by the functionclearerr().
如果文件结束,则返回非0值,否则返回0,文件结束符只能被clearerr()清除。
EOF是文本文件结束的标志。在文本文件中,数据是以字符的ASCⅡ代码值的形式存放,普通字符的ASCⅡ代码的范围是32到127(十进制),EOF的16进制代码为0xFF(十进制为-1),因此可以用EOF作为文件结束标志。[1]
当把数据以二进制形式存放到文件中时,就会有-1值的出现,因此不能采用EOF作为二进制文件的结束标志。为解决这一个问题,ASCI C提供一个feof函数,用来判断文件是否结束。feof函数既可用以判断二进制文件又可用以判断文本文件。
“C”语言的“feof()”函数和数据库中“eof()”函数的运作是完全不同的。数据库中“eof()”函数读取当前指针的位置,“C”语言的“feof()”函数返回的是最后一次“读操作的内容”。多年来把“位置和内容”相混,从而造成了对这一概念的似是而非。
那么,位置和内容到底有何不同呢?举个简单的例子,比如有人说“你走到火车的最后一节车箱”这就是位置。而如果说“请你一直向后走,摸到铁轨结束”这就是内容。也就是说用内容来判断会“多走一节”。这就是完全依赖于“while(!feof(FP)){...}”进行文件复制时,目标文档总会比源文档“多出一些”的原因。
在“C”文件读取操作时不能完全依赖于“while(!feof(FP)){...}”的判断。下面代码是改进后的代码,该代码执行后output文件内容和input文件内容一致,与使用“while(!feof(FP)){...}”相比,output文件的结尾符号(EOF)没有被读入到input文件中。
//main.c linux 下编译通过、vc下也行。
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
   FILE *in, *out;
   int ch;
   if ((in = fopen("./output.txt", "r"))== NULL) //input.txt must exist in current directory.
   {
     fprintf(stderr, "Cannot open inputfile\n");
     exit(0);
   }
   if((out=fopen("./input.txt","w"))==NULL)
   {
     fprintf(stderr,"Can not open the file.\n");
     exit(0);
   }
   while(1)
   {
     ch=fgetc(in);
     if(ch == -1)
       break;
     fprintf(stdout,"The ASC of char %c is %d\n ",ch,ch);
     fputc(ch,out);
   }
   fclose(in);
   fclose(out);
   return 0;
}
与EOF的区别
在stdio.h中可以看到如下定义:
#define EOF (-1)
#define _IOEOF 0x0010
#define feof(_stream) ((_stream)->_flag & _IOEOF)
int c;
while(!feof(fp))
{
   c = fgetc(fp);
   printf("%X\n", c);
}
会发现多输出了一个FF,原因就是在读完最后一个字符后,fp->flag仍然没有被置为_IOEOF,因而feof()仍然没有探测到文件结尾。直到再次调用fgetc()执行读操作,feof()才能探测到文件结尾。这样就多输出了一个-1(即FF)。
正确的写法应该是:
int c;
c = fgetc(fp);
while(!feof(fp))
{
  printf("%X\n", c);
  c = fgetc(fp);
}
feof()可以用EOF代替吗?不可以。fgetc返回-1时,有两种情况:读到文件结尾或是读取错误。因此我们无法确信文件已经结束, 因为可能是读取错误! 这时我们需要feof()。

1 0
原创粉丝点击