要想了解 feof(FILE* stream) 如何使用,需要我们对文件读写的几个基本概念进行澄清。
FILE 结构体由以下几个成员组成
(C95) Character width: unset, narrow, or wide.(C95) Parse state for conversions between multibyte and wide characters (an object of type mbstate_t)Buffering state: unbuffered, line-buffered, fully buffered.The buffer, which may be replaced by an external, user-provided buffer.I/O mode: input, output, or update (both input and output).Binary/text mode indicator.End-of-file status indicator.Error status indicator.File position indicator, accessible as an object of type fpos_t, which, for wide streams, includes parse state.(C11) Reentrant lock used to prevent data races when multiple threads read, write, position, or query the position of a stream.其中,FILE结构体中有一个End-of-file status indicator,当打开某个文件时,文件指针默认将End-of-file status indicator设为未达末尾,经过每一次读/写操作,该指示器就会重新更新一遍流的状态
int feof( FILE *stream );返回值 0 :未达到流stream末尾 返回值非 0 :已达到流stream末尾
判断是否达到流的末尾方式:检测文件指针stream指向的结构体中End-of-file status indicator是否已达流末尾
This function only reports the stream state as reported by the most recent I/O operation, it does not examine the associated data source. For example, if the most recent I/O was a fgetc, which returned the last byte of a file, feof returns zero. The next fgetc fails and changes the stream state to end-of-file. Only then feof returns non-zero.
In typical usage, input stream processing stops on any error; feof and ferror are then used to distinguish between different error conditions.
由于End-of-file status indicator是需要经过之前最近的一次I/O,才能得到流是否已达到末尾
如下代码:
#include <stdio.h> int main(int argc, char** argv){ FILE* fp = fopen("test.txt", "r"); //Empty File if(!fp) { perror("File opening failed"); return EXIT_FAILURE; } int counter = 0; while(!feof(fp)){ fgetc(fp); counter++; } printf("counter = %d\n", counter); fclose(fp); }test.txt为空文件,测试结果 counter = 1 而不是 0
原因就是feof通过检查fp文件指针指向的结构体中的End-of-file status indicator成员,默认是在未达到文件流结尾的状态,那么feof返回0值,进入循环,从文件中读取一个字符,发现读取不了了,将fp文件指针指向结构体中的成员End-of-file status indicator置为已达文件流末尾,counter++,再次重新进入循环时,feof检测到End-of-file status indicator为已达末尾返回1,退出循环,因此打印出counter值为1
改进: 为了避免上述情况出现,做出如下改动
int counter = 0; fgetc(fp); while(!feof(fp)){ fgetc(fp); counter++; }或
int counter = 0; while(fgetc(fp) != EOF){ counter++; } feof应用 #include <stdio.h> #include <stdlib.h> int main(void) { FILE* fp = fopen("test.txt", "r"); if(!fp) { perror("File opening failed"); return EXIT_FAILURE; } int c; // note: int, not char, required to handle EOF while ((c = fgetc(fp)) != EOF) { // standard C I/O file reading loop putchar(c); } if (ferror(fp)) puts("I/O error when reading"); else if (feof(fp)) puts("End of file reached successfully"); fclose(fp); } 影响End-of-file status indicator有这两种情况: 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 may be cleared by explicitly calling clearerr(), or as a side-effect of other operations, e.g. fseek().参考: https://en.cppreference.com/w/c/io https://en.cppreference.com/w/c/io/feof https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong