24

到目前为止,我已经掌握了EOF在文本文件末尾自动插入一个特殊字符以指示其结束的知识。但我现在觉得有必要对此进行更多澄清。我检查了谷歌和维基百科页面,EOF但他们无法回答以下问题,也没有确切的 Stack Overflow 链接。所以请帮助我:

  • 我的书说二进制模式文件根据文件目录条目中存在的字符数来跟踪文件的结尾。(与具有特殊 EOF 字符来标记结尾的文本文件相反)。那么EOF二进制文件的背景是什么?我很困惑,因为在以下程序中,我在以二进制模式!=EOF读取文件时成功使用了比较:.exe

     #include<stdio.h>
     #include<stdlib.h>
    
     int main()
     {
    
      int ch;   
      FILE *fp1,*fp2;
    
      fp1=fopen("source.exe","rb");
      fp2=fopen("dest.exe","wb");
    
      if(fp1==NULL||fp2==NULL)
      {
      printf("Error opening files");
      exit(-1);
      }
    
      while((ch=getc(fp1))!=EOF)
      putc(ch,fp2);
    
      fclose(fp1);
      fclose(fp2);
    
      }
    
  • EOF一个特殊的“字符”吗?或者它是维基百科所说的条件,计算机知道何时返回特定值(如-1EOF在我的计算机上))的条件?这种“条件”的示例是字符读取函数完成读取所有存在的字符,或者字符/字符串 I/O 函数在读取/写入时遇到错误?

    有趣的是,堆栈溢出标签EOF混合了 EOF. 用于EOF表示“在编程领域中,EOF 是一个字节序列(或一个字符)的标签,表示在此之后没有更多内容。” ,虽然它还在“关于”部分中说“文件结束(通常缩写为 EOF)是计算机操作系统中无法从数据源读取更多数据的情况。数据源通常称为文件或溪流。”

但我有一种强烈的感觉EOF,它不会是一个角色,因为在 I/O 期间遇到错误时,其他所有函数似乎都会返回它。

如果你能帮我弄清楚这件事,你会非常好。

4

5 回答 5

30

C 提供给您的各种 EOF 指示符不一定与文件系统如何标记文件的结尾有任何关系。

大多数现代文件系统都知道文件的长度,因为它们将文件记录在某个地方,与文件的内容分开。读取文件的例程会跟踪您正在阅读的位置,并在您到达末尾时停止。C 库例程生成一个 EOF 值以返回给您;他们没有返回文件中实际存在的值。

请注意,C 库例程返回的 EOF 实际上不是字符。C 库例程通常返回一个int, 并且它int是字符值EOF。例如,在一种实现中,字符可能具有从 0 到 255 的值,而 EOF 可能具有值 -1。当库例程遇到文件结尾时,它实际上并没有看到 -1 字符,因为没有这样的字符。相反,底层系统例程告诉它已经到达文件末尾,并通过向您返回-1来响应。

旧的和原始的文件系统可能在文件中有一个值来标记文件的结尾。由于各种原因,这通常是不可取的。在其最简单的实现中,无法在文件中存储任意数据,因为您无法将文件结束标记存储为数据。但是,可以有一种实现,其中文件中的原始数据包含指示文件结尾的内容,但是在读取或写入时会转换数据,以便可以存储任意数据。(例如,通过“引用”文件结束标记。)

在某些情况下,文件结束标记之类的东西也会出现在流中。这在从终端(或伪终端或类似终端的设备)读取时很常见。在 Windows 上,按下 control-Z 表示用户已完成输入,并且会以类似方式处理到达文件结尾。这并不意味着 control-Z 是 EOF。从终端读取的软件看到 control-Z,将其视为文件结束,并返回文件结束指示,这可能与 control-Z 不同。在 Unix 上,control-D 通常是一个类似的标记输入结束的标记。

于 2013-05-21T19:24:06.317 回答
2

这应该为您很好地清除它。

基本上,EOF 只是一个具有预定义值的宏,该值表示来自 I/O 函数的错误代码,表示没有更多数据要读取。

于 2013-05-21T19:13:48.133 回答
1

该文件实际上不包含 EOF。EOF 不是某种字符——记住一个字节可以在 0 到 255 之间,所以如果一个文件可以包含 -1 是没有意义的。EOF 是来自您正在使用的操作系统的信号,表示已到达文件末尾。请注意 getc() 如何返回int- ,因此它可以返回 -1 以告诉您流已到达文件末尾。

对于二进制文件和文本文件,EOF 信号的处理方式相同 - 二进制文件和文本流的实际定义因操作系统而异(例如,在 *nix 上,二进制文件和文本模式是相同的。)无论哪种方式,如上所述,它是不是文件本身的一部分。操作系统将它传递给 getc() 以告诉程序已到达流的末尾。

来自GNU C 库:

该宏是一个整数值,由许多窄流函数返回,以指示文件结束条件或其他一些错误情况。对于 GNU C 库,EOF 为 -1。在其他库中,它的值可能是其他负数。

于 2013-05-21T19:22:21.950 回答
0

EOF不是一个字符。在这种情况下,它是-1,从技术上讲,它不是一个字符(如果你想非常精确,可以说它可能是一个字符,但这与本次讨论无关)。 EOF,只是要清楚的是“文件结束”。在读取文件时,您需要知道何时停止,否则如果您尝试读取文件末尾,可能会发生许多事情,具体取决于环境

因此,设计了一个宏来表示在读取文件的过程中已到达文件结尾,即EOF. 因为getc它返回的是inta 而不是 a char,所以这是有效的,所以有额外的空间来返回 a 以外的东西char到 signal EOF。其他 I/O 调用可能会发出EOF不同的信号,例如抛出异常。

作为一个有趣的点,在 DOS 中(也许还在 Windows 上?)一个实际的物理字符^Z被放置在文件的末尾以表示它的结束。所以,在 DOS 上,实际上有一个EOF字符。Unix 从来没有这样的事情。

于 2013-05-21T19:21:07.860 回答
-1

好吧,如果您研究它的结构,几乎可以找到二进制文件的 EOF。

不,您不需要操作系统知道可执行 EOF 的 EOF。

几乎每种类型的可执行文件都有一个零页,它描述了操作系统在将代码加载到内存时可能需要的基本信息,并作为该可执行文件的第一页存储。

让我们以 MZ 可执行文件为例。 https://wiki.osdev.org/MZ

在偏移量 2 处,我们有完整/部分页面的总数,然后在偏移量 4 处,我们有最后一页的字节数。操作系统通常使用此信息将代码安全地加载到内存中,但您可以使用它来计算二进制文件的 EOF。

算法:

 1. Start
 2. Parse the parameter and instantiate the file pointer as per your requirement.
 3. Load the first page (zero) in a (char) buffer of default size of page zero and print it. 
 4. Get the value at *((short int*)(&buffer+2)) and store it in a loop variable called (short int) i.
 5. Get the value at *((short int*)(&buffer+4)) and store it in a variable called (short int) l.
 6. i--
 7. Load and print (or do whatever you wanted to do) 'size of page' characters into a buffer until i equals zero.
 8. Once the loop has finished executing just load `l` bytes into that buffer and again perform whatever you wanted to 
 9.  Stop

如果您正在设计自己的二进制文件格式,请考虑在该文件的开头添加某种元数据或表示该文件结尾的特殊字符或单词。

并且操作系统很可能会借助简单的数学运算并通过分析元数据从此处加载文件的大小,即使看起来操作系统似乎已将其与预期的其他信息一起存储在某处store(减少冗余的抽象)。

于 2020-04-06T08:02:44.193 回答