什么是二进制文件的EOF?条件?字符?

时间:2013-05-21 19:07:05

标签: c binaryfiles eof

我已经知道EOF是一个在文本文件末尾自动插入的特殊字符以表明其结束。但我现在觉得有必要对此作一些澄清。我在Google和维基百科页面上检查了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的Stack Overflow标签混合了EOF的两个定义。 EOF的标签表示“在编程领域,EOF是一个字节序列(或一个字符),表示此后没有更多内容。”,同时它也说“文件结束(通常缩写为EOF)的”约“部分是计算机操作系统中不能从数据源读取数据的条件。数据源通常称为文件或流。”

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

如果你能为我解决这个问题,那将是非常好的。

5 个答案:

答案 0 :(得分:25)

C提供给您的各种EOF指标不一定与文件系统标记文件结尾的方式有关。

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

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

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

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

答案 1 :(得分:2)

This should clear it up nicely for you.

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

答案 2 :(得分:1)

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

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

来自From the GNU C library:

  

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

答案 3 :(得分:0)

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

因此,设计了一个宏来表示在读取文件EOF的过程中已到达文件结尾。对于getc,这可行,因为它返回int而不是char,因此还有额外的空间可以返回char以外的其他内容来发信号EOF。其他I / O调用可能会以不同的方式发出EOF信号,例如抛出异常。

作为一个兴趣点,在DOS(并且可能仍在Windows?)中,实际的物理字符^Z被放置在文件的末尾以表示其结束。所以,在DOS上,实际上有一个EOF字符。 Unix从未有过这样的事情。

答案 4 :(得分:-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

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

操作系统很有可能借助简单的数学方法并通过分析元数据从此处加载文件大小,即使操作系统似乎将其与其他信息一起存储在某处它应该存储(抽象以减少冗余)。