【问题标题】:What really is EOF for binary files? Condition? Character?二进制文件的真正EOF是什么?健康)状况?特点?
【发布时间】:2013-05-16 16:05:31
【问题描述】:

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

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

     #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 是不是一个特殊的“字符”?或者它是维基百科所说的条件,计算机知道何时返回特定值,如-1(我的计算机上的EOF)?这种“条件”的例子是字符读取函数完成读取所有存在的字符,或者字符/字符串 I/O 函数在读取/写入时遇到错误?

    有趣的是,EOF 的 Stack Overflow 标记融合了 EOF 的这两个定义。 EOF 的标签表示“在编程领域,EOF 是一个字节序列(或字符),表示在此之后没有更多内容。”,同时在“关于"部分,"文件结束(通常缩写为 EOF)是计算机操作系统中无法从数据源读取更多数据的条件。数据源通常称为文件或流。" em>

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

如果你能帮我解决这件事,你会很高兴的。

【问题讨论】:

标签: c binaryfiles eof


【解决方案1】:

This should clear it up nicely for you.

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

【讨论】:

  • 感谢 Christopher。您提供的链接来自我最喜欢的网站之一。Good Ol Alex Allain!!我检查了 C 部分,但从不知道还有一个很酷的常见问题解答部分。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

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

    来自From the GNU C library:

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

    【讨论】:

      【解决方案4】:

      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 通常是一个类似的标记输入结束的标记。

      【讨论】:

        【解决方案5】:

        如果你研究它的结构,几乎可以找到二进制文件的 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
        

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-02-17
          • 1970-01-01
          • 2020-08-22
          • 1970-01-01
          • 1970-01-01
          • 2017-09-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多