feof() 实际上如何知道何时到达文件末尾?

How does feof() actually know when the end of file is reached?

提问人:Austin 提问时间:5/13/2016 最后编辑:wizzwizz4Austin 更新时间:9/17/2018 访问量:3729

问:

我是C++的初学者,并试图更好地理解.我读过这个标志只有在尝试读取文件末尾后才会设置为 true,所以很多时候初学者会比他们预期的多读一次,如果他们做这样的事情。不过,我试图理解的是,它实际上如何解释已尝试读取文件末尾?是已经读入了整个文件并且已知了字符数,还是有其他机制在起作用?feof()feof()while(!feof(file))

我意识到这可能是一个重复的问题,但我一直找不到它,可能是因为我不知道用最好的方式来表达我所问的问题。如果已经有答案,链接将不胜感激。谢谢。

C++ C FEOF

评论

0赞 kartik7153 5/13/2016
stackoverflow.com/questions/4358728/end-of-file-eof-in-c希望这对:)有所帮助
1赞 5/13/2016
对流进行映像,没有已知的限制。然后,没有其他方法可以尝试读取以获取文件末尾。(注意:文件流是不同类型输入/输出的抽象)
1赞 Creris 5/13/2016
@kartik7153这并不能回答他的问题。他询问操作系统如何具体决定何时到达文件末尾。
1赞 5/13/2016
@Jake 这是一个操作系统详细信息(这取决于使用的底层设备/协议)
1赞 alk 5/13/2016
我想说的是,最终文件系统实现决定了,由于 Linux 支持不同的文件系统,因此需要查找它们的实现代码。

答:

8赞 Sergei Tachenov 5/13/2016 #1

feof()是标准 C 库缓冲 I/O 的一部分。由于它是缓冲的,因此会预读取一些数据(但绝对不是整个文件)。如果在缓冲时检测到 EOF(基础 OS 例程通常返回一个特殊值),它会在结构上设置一个标志。 只需检查该标志即可。因此,返回 true 本质上意味着“之前的读取尝试遇到文件末尾”。fread()fread()-1FILEfeof()feof()

如何检测到的 EOF 是特定于 OS/FS 的,与 C 库/语言无关。操作系统有一些接口可以从文件中读取数据。C 库只是操作系统和程序之间的桥梁,因此如果您迁移到另一个操作系统,则不必更改程序。操作系统知道如何将文件存储在其文件系统中,因此它知道如何检测 EOF。我的猜测是,通常它是通过将当前位置与文件的长度进行比较来执行的,但它可能不是那么容易,并且可能涉及许多低级细节(例如,如果文件在网络驱动器上怎么办?

一个有趣的问题是,当流在末尾,但尚未被任何读取检测到时会发生什么。例如,如果打开一个空文件。对 before 的第一次调用是返回 true 还是 false?答案可能是错误的。文档在这个问题上不是很清楚:feof()fread()

此指示器通常由流上的先前操作设置 试图在文件末尾或文件末尾读取。

听起来好像一个特定的实现可能会选择一些其他不寻常的方法来设置这个标志。

评论

0赞 Austin 5/13/2016
谢谢。您能否详细说明一下“如果在缓冲时,fread() 检测到 EOF”?我想弄清楚的是EOF是如何实际标记的,以及如何检测它。
3赞 Gregg 5/13/2016 #2

大多数文件系统都会维护有关文件的元信息(包括其大小),并且尝试读取超过末尾会导致设置 feof 标志。其他文件系统,例如旧的或轻量级的文件系统,在到达链中最后一个块的最后一个字节时设置 feof。

评论

0赞 Austin 5/13/2016
我认为这最接近我所要求的。因此,当您这样做时,FILE 类型是否已经知道文件的大小,然后可以由 ?FILE *fp = fopen()feof()
0赞 Gregg 5/18/2016
通常,是的。元信息的一部分是文件大小(也有日期、位置、以前的版本等)。元信息与文件一起存储,并在打开文件时检索。但它实际上并不是文件系统所必需的,因此这取决于它的实现方式。
11赞 David Schwartz 5/13/2016 #3

无论 C++ 库做什么,最终它都必须从文件中读取。在操作系统的某个地方,有一段代码最终会处理该读取。它从文件系统获取文件的长度,其存储方式与文件系统存储其他所有内容的方式相同。知道文件的长度、读取的位置和要读取的字节数,它可以确定低级读取是否命中了文件的末尾。

当做出该决定时,它就会被传递到堆栈中。最终,它到达标准库,该库在内部记录已到达文件末尾。当对库的读取请求试图越过该记录的结束时,将设置 EOF 标志并开始返回 true。feof

评论

0赞 Austin 5/13/2016
谢谢,这正是我想知道的!
2赞 chux - Reinstate Monica 5/13/2016 #4

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

评论

0赞 9/17/2018
不错的代码片段。但是你的意思是最后一个字符不一定是已知的吗?
0赞 chux - Reinstate Monica 9/17/2018
@JohnSmithSr。是的,帖子修改了,你“不”对。
-2赞 Nauroze Hoath 5/13/2016 #5

该函数设置读取 EOF 字符时的文件结束指示器。因此,当读取最后一项时,EOF 最初不会随它一起读取。由于未设置 EOF 指示器并返回零,因此流将再次进入 while 循环。这一次知道下一个字符是 EOF,它丢弃它并返回 NULL,但也设置了 EOF 指标。因此,检测文件结束指示器并返回一个非零值,从而中断 while 循环。feof()feof()feof()fgetsfeof()