在英特尔爱迪生上为 python 3 设置文件系统编码



重现步骤:

  1. 创建包含内容This is 中文的文件test.txt(即 UTF-8 编码的非 ASCII 文本)。
  2. 英特尔爱迪生上自定义编译 python 3.5.2。
  3. 启动自定义编译的 python3 解释器并发出以下代码段:

    with open('test.txt', 'r') as fh:
    fh.readlines()
    

实际行为:

引发UnicodeDecodeError异常。默认情况下,文件以"ASCII"而不是"UTF-8"打开:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 8: ordinal not in range(128)

在"常规"Linux系统上,通过设置适当的语言环境可以轻松解决此问题,例如请参阅此帖子或该帖子。但是,在英特尔爱迪生上,我无法设置LC_CTYPE,因为默认的 Yocto Linux 发行版缺少语言环境(例如,请参阅此页面)。

我还尝试使用其他一些技巧,例如

import sys; sys.getfilesystemencoding = lambda: 'UTF-8'
import locale; locale.getpreferredencoding = lambda: 'utf-8'

我尝试在启动 python 解释器之前设置PYTHONIOENCODING=utf8环境变量。

但是,这些都不起作用。唯一的解决方法是将编码显式指定为open命令的命令行参数。这适用于上面的代码片段,但它不会为我正在使用的所有软件包设置系统范围的默认值(这将隐式打开文件 作为 ASCII,并且可能会也可能不会为我提供覆盖该默认行为的方法)。

设置 python 解释器默认文件系统编码的正确方法是什么?(当然,无需安装不需要的系统范围区域设置。

您可以设置LC_ALL环境变量以更改默认值:

$ python3 -c 'import locale; print(locale.getpreferredencoding())'
UTF-8
$ LC_ALL='.ASCII' python3 -c 'import locale; print(locale.getpreferredencoding())'
US-ASCII

我在OS X和CentOS 7上都对此进行了测试。

至于您的其他尝试,以下是它们不起作用的原因:

  • sys.getfilesystemencoding()仅适用于文件名(例如os.listdir()和朋友)。
  • io模块实际上并不使用locale.getpreferrredencoding()函数,因此更改模块上的函数不会产生任何影响。而是使用轻量级_bootlocale.py引导模块。更多内容见下文。
  • PYTHONIOENCODING仅适用于sys.stdinsys.stdoutsys.stdstderr

如果设置环境变量最终失败,您仍然可以修补_bootlocale模块:

import _bootlocale
old = _bootlocale.getpreferredencoding  # so you can restore
_bootlocale.getpreferredencoding = lambda *args: 'UTF-8'

这对我有用(同样在OS X和CentOS 7上,使用3.6测试):

>>> import _bootlocale
>>> open('/tmp/test.txt', 'w').encoding  # showing pre-patch setting
'UTF-8'
>>> old = _bootlocale.getpreferredencoding
>>> _bootlocale.getpreferredencoding = lambda *a: 'ASCII'
>>> open('/tmp/test.txt', 'w').encoding  # gimped hook
'ASCII'

相关内容

最新更新