在 Intel Edison 上为 python 3 设置文件系统编码
Set filesystem encoding for python 3 on the Intel Edison
重现步骤:
- 创建一个文件
test.txt
,内容为 This is 中文
(即 UTF-8 编码的非 ASCII 文本)。
- 在 Intel Edison 上自定义编译 python 3.5.2。
启动自定义编译的 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)
在 "regular" Linux 系统上,这个问题很容易通过设置合适的语言环境来解决,参见例如this post or that post. On the Intel Edison, however, I cannot set the LC_CTYPE
since the default Yocto Linux distribution is missing locales (see e.g. this page).
我还尝试使用其他一些技巧,例如
import sys; sys.getfilesystemencoding = lambda: 'UTF-8'
import locale; locale.getpreferredencoding = lambda: 'utf-8'
我尝试在启动 python 解释器之前设置 PYTHONIOENCODING=utf8
环境变量。
但是,none 是有效的。唯一的解决方法是将编码明确指定为 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
bootstrap module。更多内容见下文。
PYTHONIOENCODING
仅适用于 sys.stdin
、sys.stdout
和 sys.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'
重现步骤:
- 创建一个文件
test.txt
,内容为This is 中文
(即 UTF-8 编码的非 ASCII 文本)。 - 在 Intel Edison 上自定义编译 python 3.5.2。
启动自定义编译的 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)
在 "regular" Linux 系统上,这个问题很容易通过设置合适的语言环境来解决,参见例如this post or that post. On the Intel Edison, however, I cannot set the LC_CTYPE
since the default Yocto Linux distribution is missing locales (see e.g. this page).
我还尝试使用其他一些技巧,例如
import sys; sys.getfilesystemencoding = lambda: 'UTF-8'
import locale; locale.getpreferredencoding = lambda: 'utf-8'
我尝试在启动 python 解释器之前设置 PYTHONIOENCODING=utf8
环境变量。
但是,none 是有效的。唯一的解决方法是将编码明确指定为 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
bootstrap module。更多内容见下文。PYTHONIOENCODING
仅适用于sys.stdin
、sys.stdout
和sys.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'