龙空技术网

C|深入了解文件结束标志EOF是如何设置和检测的

小智雅汇 169

前言:

此时看官们对“c语言eof输入”大概比较关心,各位老铁们都需要分析一些“c语言eof输入”的相关内容。那么小编在网摘上网罗了一些有关“c语言eof输入””的相关资讯,希望同学们能喜欢,各位老铁们快快来了解一下吧!

C语言中文件操作是通过FILE结构体来描述的,先看一下在"stdio.h"中对FILE的定义:

struct _iobuf {    char *_ptr;      // 文件输入的下一个位置    int   _cnt;       // 当前缓冲区的相对位置    char *_base;  // 指基础位置(即是文件的其始位置)    int   _flag;      // 文件标志    int   _file;       // 文件的有效性验证    int   _charbuf;  // 检查缓冲区状况,如果无缓冲区则不读取    int   _bufsiz;    // 文件的大小    char *_tmpfname;  // 临时文件名};typedef struct _iobuf FILE;

当使用fopen()成功关联到一个文件后,返回一个FILE*指针。这个指针指向上面的结构体,用结构体的各个分量来描述文件操作的情况。与此同时,会在内存中开辟一块缓冲区,缓冲在后台处理,会让人有逐字符访问的错觉。一些文件操作函数使用FILE*指针,并会通过_cnt记录指针(缓冲区)的移动情况,并设置_flag。

例如当fgetc()函数发现输入流中不存在数据时,除了返回一个EOF,还会设置FILE 对象中的end-of-file 标记,在很多实现中这个标记用一个“位”表示。而这个标志可以通过feof()检测到。

看一下EOF(End-of-File)的原文定义:

It is a macro definition of type int that expands into a negative integral constant expression (generally, -1).

It is used as the value returned by several functions in header <cstdio> to indicate that the End-of-File has been reached or to signal some other failure conditions.

fgetc()的原文定义:

int fgetc ( FILE * stream );

Get character from stream.

Returns the character currently pointed by the internal file position indicator of the specified stream. The internal file position indicator is then advanced to the next character.

If the stream is at the end-of-file when called, the function returns EOF and sets the end-of-file indicator for the stream (feof).

If a read error occurs, the function returns EOF and sets the error indicator for the stream (ferror).

fgetc and getc are equivalent, except that getc may be implemented as a macro in some libraries.

函数feof()的功能是测试流(stream)的end-of-file 标志,当流的end-of-file 标志被设置时,feof()函数的返回值为非0 (不一定是1),否则返回int 类型的0。所以函数feof()并非是通过检查“文件读写位置标记”来判断结束的。

feof()的原文定义:

int feof ( FILE * stream );

Check end-of-file indicator.

Checks whether the end-of-File indicator associated with stream is set, returning a value different from zero if it is.

This indicator is generally set by a previous operation on the stream that attempted to read at or past the end-of-file.

Notice that stream's internal position indicator may point to the end-of-file for the next operation, but still, the end-of-file indicator may not be set until an operation attempts to read at that point.

This indicator is cleared by a call to clearerr, rewind, fseek, fsetpos or freopen. Although if the position indicator is not repositioned by such a call, the next i/o operation is likely to set the indicator again.

所以流的end-of-file 标志通常是由某些读写函数(如fgetc)设置的。也就是说,即使读到了流的结尾,end-of-file 标志也未必就一定被设置,除非再读,这时end-of-file 标志才被设置(文件读写失败也会设置)。所以这里有一个先后顺序的一步之遥。(一些其他语言用一个特殊的函数在读取之前测试文件结尾,C语言不同。)

因此feof()函数并非是用来测试流是否结束的,feof()函数是用来检测_flag的EOF值的(测试读入是如何结束的)。

以下实例就可以清晰地看到这一过程的细节:

#include <stdio.h>#include <stdlib.h>int main( void ){    // ① 新建文本文件abc.txt并写入ABC    FILE* fp;    if((fp = fopen("D:\\ABC.TXT","w")) == NULL )    {        printf("打开文件失败\n");        return !0;    }    fputs("ABC",fp);    fclose(fp);    	// ② 打开文件,循环调用fgetc()和feof()    FILE *abc;    if((abc = fopen("D:\\abc.TXT","rb")) == NULL )    {        printf("打开文件失败\n");        return !0;    }    for(int i = 0 ; i < 5 ; i++ )    {        int ch;        int eof_before_read;		int eof_after_read;        eof_before_read = feof(abc) ;        ch = fgetc( abc );        eof_after_read = feof(abc) ;        printf(            "读入%c(%d)前后feof()的值分别为:%d,%d\n",            ch,ch,eof_before_read,eof_after_read            );    }    fclose(abc);    getchar();    return 0;}/*读入A(65)前后feof()的值分别为:0,0读入B(66)前后feof()的值分别为:0,0读入C(67)前后feof()的值分别为:0,0读入(-1)前后feof()的值分别为:0,16读入(-1)前后feof()的值分别为:16,16*/

由此不难看出,在读入缓冲区中最后一个字母C 之后(已经到了流的结尾),feof()函数的返回值依然是0,只是再次试图读取下一个字符时,feof()函数的返回值才成了16。这是由于fgetc()函数发现已经没有字符可读,在对应的FILE 结构体数据中设置了end-of-file 标记的缘故。

由此,以下判断文件是否结束的写法是错的,会相差一个字符:

while(!feof(in)){    ch=fgetc(in);    fputc(ch,out);    putchar(ch);}

正确的写法可以是:

#include <stdio.h>#include <stdlib.h>void file_copy(FILE * , FILE * );int main( void ){    FILE *abc;    FILE *abc_b;    if((abc = fopen("D:\\abc.TXT","rb")) == NULL )    {        printf("打开文件失败\n");        return EXIT_FAILURE;    }    if((abc_b = fopen("D:\\ABC_B.TXT","wb")) == NULL )    {        printf("打开文件失败\n");        return EXIT_FAILURE;    }    file_copy( abc_b , abc );    if( feof(abc) != 0 )    {        printf("拷贝正常结束\n");        fclose(abc);        fclose(abc_b);        return EXIT_SUCCESS;    }    if( ferror (abc) != 0 )    {        printf("拷贝过程中发生错误,目标文件可能并不正确\n");        fclose(abc);        fclose(abc_b);        return EXIT_FAILURE;    }}void file_copy( FILE * t, FILE *s ){int ch;while( (ch = fgetc(s) ) != EOF )    fputc( ch , t );}

在windows环境下,使用scanf()检测stdin的EOF时使用“ctrl+z”。

-End-

标签: #c语言eof输入 #c语言怎么使输入语句eof #c语言的eof是什么意思 #c语言文件结尾