【问题标题】:How EOF is defined for binary and ascii files如何为二进制和 ascii 文件定义 EOF
【发布时间】:2016-04-19 06:15:54
【问题描述】:

我在 Windows 上编程 C(系统语言是日语),我遇到了二进制和 ascii 文件的 EOF 问题。

上周我问了this question,一位好心人帮助了我,但我仍然无法真正理解程序在读取二进制文件或 ascii 文件时是如何工作的。

我做了以下测试:

测试1:

int oneChar;
iFile = fopen("myFile.tar.gz", "rb");
while ((oneChar = fgetc(iFile)) != EOF) {
        printf("%d ", oneChar);
}

测试2:

int oneChar;
iFile = fopen("myFile.tar.gz", "r");
while ((oneChar = fgetc(iFile)) != EOF) {
        printf("%d ", oneChar);
}

在 test1 案例中,二进制文件和 ascii 文件都运行良好。但在 test2 中,程序在二进制文件中遇到 0x1A 时停止读取。 (这是否意味着 1A == EOF?)ASCII 表告诉我 1A 是一个名为 substitute 的控制字符(不管这意味着什么......)当我 printf( "%d", EOF),但是,它给了我 -1...

我还找到了this question,它告诉我操作系统确切地知道文件的结束位置,所以我真的不需要在文件中找到 EOF,因为 EOF 超出了一个字节的范围(1A 怎么样?)

有人可以帮我澄清一下吗?提前致谢。

【问题讨论】:

  • 下面是关于你遇到的0x1A的char的一些解释:en.wikipedia.org/wiki/Substitute_character
  • 您是如何确定它在 0x1A 处停止读取的?如果它在其输出末尾打印数字 26 (0x1A),这意味着它正常读取该字节,但在尝试读取 之后的任何内容时得到 EOF。如果 0x1A 是 EOF,您根本不会在输出中看到该值。
  • 我最后使用了 system("PAUSE") 。所以在 Test1 案例中,它打印为:1 23 43 ... 150 26 46 ... 按任意键继续,但在 Test2 中,它打印为:1 23 43 ... 150 按任意键继续。在 Test1 中,打印了 26,但在 Test2 中,26 之前的数字 150 是它打印的最后一个字符。所以我认为在 Test2 中,26 使 (oneChar = fgetc(iFile)) != EOF 成为错误陈述

标签: c windows file


【解决方案1】:

这是针对文本文件的特定于 Windows 的技巧:SUB 字符,由 Ctrl+Z 序列表示,被解释 作为EOFfgetc。您不必在文本文件中包含1A 即可从fgetc 返回EOF,但是:一旦到达文件的实际末尾,将返回EOF

标准没有将1A 定义为char 值来表示EOFEOF 的常量是 int 类型的,其负值超出了 unsigned char 的范围。其实fgetc之所以返回int,而不是char,是为了让它为EOF返回一个特殊的值。

【讨论】:

  • 这是否意味着使用其他读取方法(例如getchar())代替fgetc()可以解决问题?
  • @CHEN 使用getchar 不会解决这个问题,但是以二进制模式打开文件会解决这个问题(当然,你已经通过实验知道了)。
【解决方案2】:

使用 Ctrl-Z 结束文件的惯例起源于 CP/M,这是一个用于 8080/Z80 微型计算机的非常古老的操作系统。它的文件系统没有将文件大小跟踪到字节级别,只跟踪到 128 字节的扇区级别,因此需要另一种方法来标记文件结束。

Microsoft 的 DOS 尽可能与 CP/M 兼容,因此它在读取文本文件时保持惯例。此时文件大小由文件系统保留,因此并非绝对必要,只是为了向后兼容而保留。

这一惯例在 Windows 的 C 和 C++ 库中一直沿用至今;当您以文本模式打开文件时,会检查每个字符的 Ctrl-Z 并设置文件结束标志(如果检测到)。您会看到向后兼容性的影响发挥到了极致,回到了将近 40 年历史的系统。

【讨论】:

  • “起源于”CP/M?当然,CP/M 是 Ctrl-Z 作为 EOF 的早期用户,但首先呢?假设我需要查找一些新石器时代的平板电脑才能显示其他信息。
  • @chux 你是对的,根据Wikipedia,它起源于 DEC,被 CP/M复制。 CP/M 无疑是 DOS 拥有它的原因。
  • 维基提到 DEC 使用它 - 也许它起源甚至更早于计算机知识的长期迷雾。 IAC Ctrl-Z 看起来像个优秀的程序员 epitaph
【解决方案3】:

找到了一篇回答所有问题的绝妙文章! https://latedev.wordpress.com/2012/12/04/all-about-eof/

【讨论】:

    【解决方案4】:

    文本文件中的 EOF 通常是字符 0x1AASCII 26(如果您愿意)。

    【讨论】:

      猜你喜欢
      • 2017-07-11
      • 2013-08-22
      • 2021-01-07
      • 2015-03-13
      • 1970-01-01
      • 2015-04-08
      • 2010-09-21
      • 1970-01-01
      • 2012-03-05
      相关资源
      最近更新 更多