无法读取 ASCII 字符 26?

3
我在文本模式下将流写入文件中。
# python code
f = open("somewhere in my computer","w")
f.write("Hello\nWorld")
f.write(chr(26)) # writing ascii character #26 to file 
f.write("hhh")
f.close()

我无法读取ASCII字符#26之后的字节。我知道应该使用二进制模式打开文件。 ASCII字符#26是 EOF 字符吗?如您所知,没有这样的东西,即不存在 EOF 字符。那么问题在哪里?这是操作系统相关的问题吗?(我在Microsoft Windows中尝试过)。


我认为在类Unix系统中,文本文件和二进制文件没有区别。 - Hesam Qodsi
可能是Windows的问题,我得到了15。 - Kevin
这太荒谬了。微软Windows使用文件内容来确定文件结尾。 - Hesam Qodsi
7
我知道我应该使用二进制模式打开文件。那就这么做吧。在DOS/Windows中,以文本模式打开的文件将ASCII 26(控制-Z)解释为文件结束符,尽管在ASCII标准中并不存在所谓的文件结束字符。这是一个特定于操作系统的怪异行为 - 几乎所有其他现代操作系统都不会这样做(虽然可能仍有其他操作系统存在此问题,因此我不会断言这一点)... - twalberg
1
另一方面,我认为当您开发应用程序时,考虑该应用程序将与其运行环境(操作系统、库、框架、API等)交互的每个细节是您的工作。这将包括如何在特定环境中正确打开和解析文件,以及许多其他细节... @HesamQodsi - twalberg
显示剩余6条评论
2个回答

3
问题是由于Windows引起的。0x1A代表Ctrl-Z,而DOS将其用作文件结束标记。Python使用Windows CRT函数_wfopen,它实现了“Ctrl-Z是EOF”的语义。
如果您的文件大小不是128字节的倍数,那么您需要一种标记文本末尾的方法。这篇文章暗示Ctrl-Z的选择基于DEC使用的更古老的惯例。

1

这段代码可以帮助我在Windows上打开并读取文件。此外,使用curses,您可以获得文件中任何控制字符的"^"表示。

import curses.ascii

filename = "myfile.txt"
f = open(filename,"w")
f.write("Hello\nWorld")
f.write(chr(26)) # writing ascii character #26 to file 
f.write("hhh")
f.close()

with open(filename,'r') as f:
    for line in f:
        line2 = [ curses.ascii.unctrl(c) if curses.ascii.iscntrl(c) else c for c in line]
        print("".join(line2))

输出: Hello Worldhhh

1
你在使用Python 3吧?如果是的话,那很有趣,这意味着他们不再依赖底层的C库来读取文件了。 - Mark Ransom
@MarkRansom:这可能与Python 3本地的str类型是Unicode有关。由于字符现在是代码点而不是字节,因此不将U+001A特殊解释是有道理的。 - MestreLion
今天我又遇到了这个问题,并进行了进一步的测试。Python 3确实不会在26处停止,我能够使用latin-1编码读取整个文件。即使如此,它确实将\r\n转换为\n。如果我在Python 2中使用codecs.open(..., 'r', encoding='latin-1'),它会像Python 3一样转换为Unicode,但它不会在26处停止,但它也不会转换\r\n - 它就像一个带有Unicode转换的二进制文件。 - Mark Ransom
@MestreLion,这与Unicode无关,这只是Windows文本文件的遗留约定。更可能的是,由于Python 3允许破坏性变化,有人决定该约定已过时并应被废弃。 - Mark Ransom

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