为什么 Python3 在 Windows 上使用“surrogatepass”文件系统错误处理程序?

问题描述 投票:0回答:1

对于 Python 3(3.8 和之前的版本回到 3.6),

surrogatepass
是默认的错误处理程序。

对于文件路径与此编码不匹配的用户来说,这可能会导致问题。

为什么 Windows 使用 surrogatepass

而不是像其他平台(Linux、macOS)那样使用

surrogateescape

,后者可以处理这些字节。例如:
>>> import sys

>>> sys.getfilesystemencoding(), sys.getfilesystemencodeerrors()
('utf-8', 'surrogateescape')
>>>
>>> # This raises an error:
>>>
>>> b'C:\\Users\\me\\OneDrive\\\xe0\xcd\xa1\xca\xd2\xc3\\my.txt'.decode('utf-8', errors="surrogatepass")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 24: invalid continuation byte

>>> # Compared to:

>>> b'C:\\Users\\me\\OneDrive\\\xe0\xcd\xa1\xca\xd2\xc3\\my.txt'.decode('utf-8', errors="surrogateescape")
'C:\\Users\\me\\OneDrive\\\udce0͡\udcca\udcd2\udcc3\\my.txt'

注意,我猜测这可能是必要的,因为底层 NTFS 文件系统使用 UTF-16 而不是空终止字节,需要对 Linux/macOS 上不存在的 Python 文件系统编码进行一些限制。

根本原因是Windows和*nix采用完全不同的方式来采用unicode。
python-3.x encoding utf-8 filesystems
1个回答
0
投票
Windows NT 在其设计中深入采用了原始的 16 位 unicode 1.x。它提供 8 位和 16 位 API,但 8 位 API 非常“传统”。从第一个版本开始,它的本机文件系统就使用 16 位 Unicode。

同样,当 MS 为 FAT(在实现它的驱动程序之后称为“vfat”)和 ISO9660(称为 Joliet)开发“长文件名”扩展时,这些扩展都是基于 16 位 Unicode 的。

然而 16 位 Unicode 时代并没有持续太久。特别是来自中国的强大压力,要求不仅对当前汉字进行编码,还要对历史汉字进行编码。同样,软件供应商也不想再次迁移文本格式。结果就是 UTF-16,一种使用 16 位代码单元的可变宽度编码,是原始 16 位编码的扩展。

与此同时,类 Unix 系统仍然坚持使用 8 位字节作为其基本文本单位。 UTF-8 被视为另一种面向字节的扩展 ASCII 编码,随着时间的推移,它逐渐取代了其他扩展 ASCII 编码。

在这两种情况下,程序都可能从操作系统接收在假定编码中无效的字符串。此外,在某些情况下,特别是涉及文件名的情况下,有必要处理这些字符串并将它们以无损的方式传递回操作系统。

这就是为什么 python 3 中添加了“surrogatepass”和“surrogateescape”编码选项的原因。

“surrogateescape”是为扩展 ascii 编码而设计的。当与这种编码一起使用时,它允许将任何字节序列转换为 python 字符串,并将生成的 python 字符串转换回字节序列,而不会丢失任何信息。 Python 允许您使用 UTF-16 指定“surrogateescape”,但它似乎实际上并不能正常工作,而且没有意义。

“surrogatepass”专为与 UTF-16 一起使用而设计。与 UTF-16 一起使用时,它允许将任何 16 位单元序列转换为 python 字符串,然后再转换回原始 16 位单元序列。它可以与其他 Unicode 编码一起使用,并且在某些情况下这样做可能有意义,但有大量无效的 UTF-8 序列在指定“surrogatepass”时仍然无效。

© www.soinside.com 2019 - 2024. All rights reserved.