【发布时间】:2016-07-15 17:50:30
【问题描述】:
我认为这是 Unicode 世界的警告 -> 在不知道编码是什么的情况下,您无法正确将字节流处理为写入。如果您采用编码,那么您可能会显示有效但不正确的字符。
这是一个测试 - 一个带有文字的文件:
hi1
hi2
以 2 字节 Unicode 编码存储在磁盘上:
Windows 换行符以\r\n 存储为四字节序列0D 00 0A 00。在 Python 2 中使用默认编码打开它,我认为它需要 ASCII 1-byte-per-character(或只是一个字节流),它显示:
>>> open('d:/t/hi2.txt').readlines()
['\xff\xfeh\x00i\x001\x00\r\x00\n',
'\x00h\x00i\x002\x00']
它不是将两个字节解码为一个字符,但是四个字节的行结束序列已被检测为两个字符,文件已正确拆分为两行 .
Windows 以“文本模式”打开文件,如下所述:Difference between files writen in binary and text mode
并将这些行提供给 Python。但是,根据问题顶部的警告,Windows 是如何知道文件是多字节编码的,并在不被告知的情况下查找四字节的换行符?
- Windows 是否猜测,具有启发式 - 因此可能是错误的?
- Unicode 的设计是否更巧妙,使 Windows 换行符模式在各种编码中明确无误?
- 我的理解是否错误,是否有正确的方法来处理任何文本文件而无需事先告知编码?
【问题讨论】:
-
Windows 没有“文本模式”的概念。您说的是 C 运行时,但默认为 ANSI 文本模式,它不会检测到 UTF-16
\r\x00\n\x00序列。您实际看到的是 Python 2 中file.readlines方法的实现。请参见第 1717 行、p = (char *)memchr(buffer+nfilled, '\n', nread),然后是第 1749 行、line = PyString_FromStringAndSize(q, p-q)。它天真地消耗了一个\n字符,这就是实际的 UTF-16LE\n\x00被拆分的原因。 -
Windows 没有“文本模式”的概念 - fopen() at MSDN - “在文本模式下,回车-换行组合在输入时被转换为单个换行,和换行字符在输出时转换为回车换行组合。当 Unicode 流 I/O 函数在文本模式(默认)下运行时,源或目标流被假定为多字节字符序列。”。但是,Unicode 换行符四边形被 Python 破坏是有道理的,这可能是我的答案。
-
微软的
_open、fopen、_read、fread等都是C运行时函数。它们本质上不是 Windows 文件 I/O 的一部分,即CreateFile、ReadFile等。使用 Microsoft 的 CRT 是可选的。您可以使用没有“文本模式”的不同 CRT,或者您可以直接使用 Windows API。碰巧 Windows Python 是使用 MSVC 构建的,并使用 CRT 的低 I/O 和标准 I/O 运行时函数来促进与 Linux 和 OS X 等 POSIX 操作系统的跨平台兼容性。 -
@eryksun 然后,如果您将指向 Python 源的链接放在完整答案而不是评论中,我会将其标记为已接受。谢谢。