如何为二进制和ASCII文件定义EOF

4

我正在Windows上编写C程序(系统语言是日语),并且我在处理二进制和ASCII文件的EOF问题方面遇到了问题。

我上周询问了这个问题,有位好心人帮助了我,但我仍然无法真正理解读取二进制或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);
}

在测试1中,二进制和ASCII文件都能正常运行。但在测试2中,当程序在一个二进制文件中遇到0x1A时就停止了读取。(这是否意味着1A == EOF?)ASCII表告诉我1A是一种控制字符,称为substitute(不知道是什么意思...)。当我printf("%d", EOF)时,它却给了我-1...

我还发现了这个问题,它告诉我操作系统确切地知道文件何时结束,所以我实际上不需要在文件中找到EOF,因为EOF超出了一个字节的范围(那1A呢?)

有人能帮我澄清一下吗?先谢谢了。


以下是关于你遇到的字符0x1A的一些解释:https://en.wikipedia.org/wiki/Substitute_character - Guillaume George
你是如何确定它在0x1A处停止读取的?如果它在输出末尾打印了数字26(0x1A),那么这意味着它正常读取了该字节,但在尝试读取其后面的任何内容时遇到了EOF。如果0x1A是EOF,你根本看不到该值在输出中。 - Wyzard
我在结尾处使用了system("PAUSE")。所以在Test1的情况下,它打印如下:1 23 43 ... 150 26 46 ... 按任意键继续,但是在Test2的情况下,它打印如下:1 23 43 ... 150 按任意键继续。在Test1中,会打印出 26,但在Test2中,打印出的最后一个字符是 150 前面的数字。因此,我认为在Test2中,26 使得 (oneChar = fgetc(iFile)) != EOF 成为了 false。 - Eumaa
4个回答

8

这是一个针对文本文件的Windows专用技巧:SUB字符,它由Ctrl+Z序列表示,被fgetc“解释”为EOF。您不必在文本文件中放置1A才能从fgetc获得EOF,一旦到达实际的文件结尾,EOF将会被返回。

标准并没有定义1A作为表示EOFchar值。常量EOF的类型为int,其负值超出了unsigned char的范围。事实上,fgetc返回int而不是char的原因是为了让它返回一个特殊值,表示EOF


这是否意味着使用其他读取方法(例如getchar())而不是fgetc()可以解决问题? - Eumaa
1
@CHEN 使用 getchar 并不能解决这个问题,但是以二进制模式打开文件可以解决(当然,你已经通过实验知道了这一点)。 - Sergey Kalinichenko

5
以Ctrl-Z作为文件结尾的惯例起源于CP/M,这是一种用于8080/Z80微型计算机的非常古老的操作系统。它的文件系统只能跟踪到128字节扇区级别,而不能跟踪到字节级别,因此需要另一种方法来标记文件的结束。
Microsoft的DOS被设计成尽可能与CP/M兼容,因此在读取文本文件时保留了这个惯例。但到了那个时候,文件大小已经由文件系统保存,因此这并不是严格必要的,只是为了向后兼容而保留下来。
在Windows的C和C++库中,这个惯例一直持续到今天;当你以文本模式打开一个文件时,每个字符都会被检查是否为Ctrl-Z,并在检测到时设置文件结束标志。这是向后兼容性被推至极致的结果,回到了将近40年前的系统。

“originated” with CP/M?当然,CP/M是Ctrl-Z作为EOF的早期用户,但是第一个吗?我想我需要查一些新石器时代的牌匾来证明否则。 - chux - Reinstate Monica
@chux 你说得对,根据Wikipedia的说法,它起源于DEC,并被CP/M“复制”。 CP/M无疑是DOS拥有它的原因。 - Mark Ransom
维基提到 DEC 使用 它 - 也许它甚至在计算机传说的久远迷雾中起源。IAC Ctrl-Z 看起来像一个好的程序员 墓志铭 - chux - Reinstate Monica

0

0

文本文件中的EOF通常是字符0x1A或者ASCII 26


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接