内置函数`open`用于编码和解码文件名的机制是什么?

时间:2017-04-10 18:11:19

标签: python unicode encoding

我对open有点困惑。我正在运行Windows 10,当我致电sys.getfilesystemencoding时,我得到mbcs所以如果我将文件名传递给open,例如:

open('Meow!.txt')

据说,源文件的编码是utf-8。 open是否使用设置为默认Windows ANSI代码页的'Meow!.txt'编码对文件名mbcs进行编码?然后将请求传递给操作系统?

  • 一般来说,当您将文件名作为2.X中的unicode和3.X中的open传递给str时会发生什么?

  • 当文件名作为3.X中的bytes对象或2.X中的str传递时,是否为真,会覆盖文件名的默认自动编码?

1 个答案:

答案 0 :(得分:1)

以下是在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编码,您可以使用Py_FileSystemDefaultEncoding调用来检查sys.getfilesystemencoding()的值:

  

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和3.X中的open传递给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 ,这将为您提供å¼.txt文件名。总之,显然没有转换Unicode文件名。我认为此规则也适用于str。由于2.X中的str是原始字节字符串,因此Python不会神奇地选择编码**但我无法验证这一点,并且Python可能会使用“mbcs”编码解码str。通过使用“mbcs”代码页字符集之外的字符可以验证我是否相信,但这又取决于您的Windows语言环境设置。在Windows实现中封装了较低级别。如果内存服务,我认为“mbcs”现在被认为是Windows API的遗产。 Python 3.6使用UTF-8,除非启用了传统模式。

实际上,似乎问题深入到了Windows API及其实现,而不是Python本身的实现。