提问人:Austin 提问时间:5/13/2016 最后编辑:wizzwizz4Austin 更新时间:9/17/2018 访问量:3729
feof() 实际上如何知道何时到达文件末尾?
How does feof() actually know when the end of file is reached?
问:
我是C++的初学者,并试图更好地理解.我读过这个标志只有在尝试读取文件末尾后才会设置为 true,所以很多时候初学者会比他们预期的多读一次,如果他们做这样的事情。不过,我试图理解的是,它实际上如何解释已尝试读取文件末尾?是已经读入了整个文件并且已知了字符数,还是有其他机制在起作用?feof()
feof()
while(!feof(file))
我意识到这可能是一个重复的问题,但我一直找不到它,可能是因为我不知道用最好的方式来表达我所问的问题。如果已经有答案,链接将不胜感激。谢谢。
答:
feof()
是标准 C 库缓冲 I/O 的一部分。由于它是缓冲的,因此会预读取一些数据(但绝对不是整个文件)。如果在缓冲时检测到 EOF(基础 OS 例程通常返回一个特殊值),它会在结构上设置一个标志。 只需检查该标志即可。因此,返回 true 本质上意味着“之前的读取尝试遇到文件末尾”。fread()
fread()
-1
FILE
feof()
feof()
如何检测到的 EOF 是特定于 OS/FS 的,与 C 库/语言无关。操作系统有一些接口可以从文件中读取数据。C 库只是操作系统和程序之间的桥梁,因此如果您迁移到另一个操作系统,则不必更改程序。操作系统知道如何将文件存储在其文件系统中,因此它知道如何检测 EOF。我的猜测是,通常它是通过将当前位置与文件的长度进行比较来执行的,但它可能不是那么容易,并且可能涉及许多低级细节(例如,如果文件在网络驱动器上怎么办?
一个有趣的问题是,当流在末尾,但尚未被任何读取检测到时会发生什么。例如,如果打开一个空文件。对 before 的第一次调用是返回 true 还是 false?答案可能是错误的。文档在这个问题上不是很清楚:feof()
fread()
此指示器通常由流上的先前操作设置 试图在文件末尾或文件末尾读取。
听起来好像一个特定的实现可能会选择一些其他不寻常的方法来设置这个标志。
评论
大多数文件系统都会维护有关文件的元信息(包括其大小),并且尝试读取超过末尾会导致设置 feof 标志。其他文件系统,例如旧的或轻量级的文件系统,在到达链中最后一个块的最后一个字节时设置 feof。
评论
FILE *fp = fopen()
feof()
无论 C++ 库做什么,最终它都必须从文件中读取。在操作系统的某个地方,有一段代码最终会处理该读取。它从文件系统获取文件的长度,其存储方式与文件系统存储其他所有内容的方式相同。知道文件的长度、读取的位置和要读取的字节数,它可以确定低级读取是否命中了文件的末尾。
当做出该决定时,它就会被传递到堆栈中。最终,它到达标准库,该库在内部记录已到达文件末尾。当对库的读取请求试图越过该记录的结束时,将设置 EOF 标志并开始返回 true。feof
评论
feof() 实际上如何知道何时到达文件末尾?
当代码尝试读取时,传递了最后一个字符。
根据文件类型,最后一个字符不一定是已知的,直到尝试读取它并且没有可用的字符。
演示从 0 到 1 的示例代码feof()
#include <stdio.h>
void ftest(int n) {
FILE *ostream = fopen("tmp.txt", "w");
if (ostream) {
while (n--) {
fputc('x', ostream);
}
fclose(ostream);
}
FILE *istream = fopen("tmp.txt", "r");
if (istream) {
char buf[10];
printf("feof() %d\n", feof(istream));
printf("fread %zu\n", fread(buf, 1, 10, istream));
printf("feof() %d\n", feof(istream));
printf("fread %zu\n", fread(buf, 1, 10, istream));
printf("feof() %d\n", feof(istream));
puts("");
fclose(istream);
}
}
int main(void) {
ftest(9);
ftest(10);
return 0;
}
输出
feof() 0
fread 9 // 10 character read attempted, 9 were read
feof() 1 // eof is set as previous read attempted to read passed the 9th or last char
fread 0
feof() 1
feof() 0
fread 10 // 10 character read attempted, 10 were read
feof() 0 // eof is still clear as no attempt to read passed the 10th, last char
fread 0
feof() 1
评论
该函数设置读取 EOF 字符时的文件结束指示器。因此,当读取最后一项时,EOF 最初不会随它一起读取。由于未设置 EOF 指示器并返回零,因此流将再次进入 while 循环。这一次知道下一个字符是 EOF,它丢弃它并返回 NULL,但也设置了 EOF 指标。因此,检测文件结束指示器并返回一个非零值,从而中断 while 循环。feof()
feof()
feof()
fgets
feof()
评论