fseek 超出文件末尾的位置不会通过 feof 触发 EOF,为什么?

17

我正在从一个使用以下方式打开的文件中读取数据到内存中:

FILE *f = fopen(path, "rb");

在开始从文件中复制字节之前,我使用以下方法将指针定位到起始位置:

/**                                                                                                                                                    
 * Goes to the given position of the given file.                                                                                                       
 *                                                                                                                                                     
 * - Returns 0 on success                                                                                                                              
 * - Returns -1 on EOF                                                                                                                                 
 * - Returns -2 if an error occured, see errno for error code                                                                                          
 * - Returns -3 if none of the above applies. This should never happen!                                                                                
 */                                                                                                                                                    

static int8_t goto_pos(FILE *f, uint64_t pos)                                                                                                          
{                                                                                                                                                      
        int err = fseek(f, pos, SEEK_SET);                                                                                                             

        if (err != 0) {                                                                                                                                
                if (feof(f) != 0) return -1;                                                                                                           
                if (ferror(f) != 0) return -2;                                                                                                         
                return -3;                                                                                                                             
        }                                                                                                                                              

        return 0;                                                                                                                                      
}

问题是,尽管我寻求的位置远远超过了EOF,但此函数从未返回-1。

根据参考文献,当遇到EOF时,feof应该返回非零值。

为什么会这样?feof函数无用吗?


请注意,我目前正在使用fgetc的返回值来检查EOF


1
在fseek文档的哪里看到它会设置EOF标志? - Mat
1
@alk: 为什么你觉得需要表现得居高临下呢?这样做不会给我或其他人带来帮助。 - rzetterberg
1
我并不是说个人攻击你。请原谅我有点讽刺地试图推动人们阅读文档。顺便说一句:通常最好阅读工具自带的文档,例如在Linux下随开发工具链提供的man页面。 - alk
@alk:谢谢,没关系。就像我对Mat说的那样,我已经阅读了文档。只是有时候你会错过一些东西,特别是当你对API或编程语言不熟悉的时候。也许手册是最好的参考? - rzetterberg
1
如果出现不确定情况,建议咨询多个信息来源。一个好的参考标准是:http://pubs.opengroup.org/onlinepubs/9699919799/idx/functions.html(POSIX),GNU libc中有关内容的概述:http://www.gnu.org/software/libc/manual/html_node/Function-Index.html#Function-Index,最后可以从此处阅读源代码的man页面:http://manpages.debian.net/cgi-bin/man.cgi(**没有**任何烦人的广告!) - alk
显示剩余5条评论
4个回答

21

仅仅使用 seek 操作并不能检测文件是否已经结束。

原因是,您可能希望在进行 fwrite() 操作时执行 seek 操作,但是 fseek() 并不知道调用后的后续计划。

如果您在文件结尾位置向后执行 fread() 操作,那么 feof() 将会返回非零值。


13
不仅仅是寻找函数不测试文件结尾标志(eof),而且它还清除了该标志。 - R.. GitHub STOP HELPING ICE
谢谢您的解释!那么对我来说feof没有用处,因为我正在使用fgetc并检查EOF返回值。 - rzetterberg
1
OP在打开流时使用了"rb"模式,这种fseek行为对于只读文件没有任何意义。 - malat

7
寻找超出EOF的位置将在随后的写入后扩大文件大小,与其他人所认为的相反,这是符合规范的。请参见此处: fseek 引用块: fseek()函数应允许设置文件位置指示器超出文件中现有数据的末尾。 如果稍后在此点写入数据,则对于间隙中的数据的随后读取将返回值为0的字节,直到实际写入间隙的数据。
这就是为什么fseek不能返回EOF,如果您尝试从先前未写入该位置或其后面的位置读取数据,则稍后会得到EOF。 所以这都是正确的行为。

6

feof()在读取尝试失败后设置,因此需要先执行fgets()fread()


3
在某些操作系统上,如果超过文件结尾继续查找,会增加文件的大小。只要还有空间使文件变大,它就不会返回错误。

1
你能提供一个参考吗? - Matt Joiner
1
在某些操作系统上寻找文件结尾之外的内容会增加文件大小。我怀疑这不符合C标准。 - alk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接