我对open
有点困惑。我正在运行 Windows 10,当我调用sys.getfilesystemencoding
时,我会得到mbcs
,因此如果我将文件名传递给open
例如:
open('Meow!.txt')
据推测,源文件的编码是 utf-8。open
是否使用设置为默认 Windows ANSI 代码页的mbcs
编码对文件名'Meow!.txt'
进行编码?然后将请求传递给操作系统?
一般来说,当您在 2.X 中将文件名作为 unicode 传递给
open
并在 3.X 中将str
传递给时会发生什么?当文件名在 3.X 中作为
bytes
对象传递或在 2.X 中作为str
对象传递时,是否覆盖文件名的默认自动编码?
准确地说,这是在 2.7 中使用内置open
时内部发生的情况:
Python 设置了一个常量,用于命名文件名的默认编码,此常量称为Py_FileSystemDefaultEncoding
,并且因平台而异。最终,当其值设置为 Null 时,Python 将尝试获取平台的默认编码(如果有):
/*bltinmodule.c*/
/* The default encoding used by the platform file system APIs
Can remain NULL for all platforms that don't have such a concept
*/
#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T)
const char *Py_FileSystemDefaultEncoding = "mbcs";
#elif defined(__APPLE__)
const char *Py_FileSystemDefaultEncoding = "utf-8";
#else
const char *Py_FileSystemDefaultEncoding = NULL; /* use default */
#endif
Py_FileSystemDefaultEncoding
使用"mbcs"(多字节字符集)Windows编码,则可以使用sys.getfilesystemencoding()
调用来检查Py_FileSystemDefaultEncoding
的值:
Python 2.7 文档:
sys.getfilesystemencoding()
在 Windows NT+ 上,文件名是本机的 Unicode,因此不执行转换。
getfilesystemencoding()
仍然返回"mbcs",因为这是应用程序在明确希望将 Unicode 字符串转换为用作文件名时等效的字节字符串时应使用的编码。
例如,让我们假设当一个带有中文字符的文件名时,为简单起见,我将使用 U+5F08 中国象棋 CJK 作为我要写的文件名:
>>> f = open(u'u5F08.txt', 'w')
>>> f
<open file u'u5f08', mode 'w' at 0x000000000336B1E0>
- 一般来说,当您在 2.X 中将文件名作为 unicode 传递给
open
并在 3.X 中将str
传递给时会发生什么?
此答案取决于平台。例如,在Windows中,不需要将Unicode字符串转换为任何编码,即使使用默认的文件系统编码"mbcs",也不需要证明:
>>> f = open(u'u5F08.txt'.encode('mbcs'), 'w')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 22] invalid mode ('w') or filename: '?.txt'
顺便说一下,即使您使用"utf-8"编码,也不会获得正确的文件名:
>>> f = open(u'u5F08.txt'.encode('utf8'), 'w')
如果你在Windows上检查它而不是弈.txt,这将给你å1/4ˆ.txt文件名。总之,显然没有Unicode文件名的转换。我认为这条规则也适用于str
。由于 2.X 中的str
是一个原始字节字符串,Python 不会神奇地选择编码 **但是我无法验证这一点,Python 可能会使用 "mbcs" 编码解码str
。可以通过使用"mbcs"代码页字符集之外的字符来验证我相信,但这同样取决于您的 Windows 区域设置。在Windows实现中,很多东西都封装在较低级别。如果没记错的话,我认为"mbcs"现在被认为是Windows API的遗留问题。 Python 3.6 改用 UTF-8,除非启用了传统模式。
实际上,问题似乎在于Windows API及其实现,而不是Python本身的实现。