Python 3.x 在Intel Edison上为python 3设置文件系统编码
复制步骤:Python 3.x 在Intel Edison上为python 3设置文件系统编码,python-3.x,character-encoding,intel-edison,Python 3.x,Character Encoding,Intel Edison,复制步骤: 创建一个文件test.txt,内容如下中文(即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' c
test.txt
,内容如下中文代码>(即UTF-8编码的非ASCII文本)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系统上,通过设置适当的区域设置可以轻松解决此问题,请参阅或。但是,在Intel Edison上,我无法设置LC_CTYPE
,因为默认的Yocto Linux发行版缺少区域设置(请参见示例)
我还尝试使用了一些其他的黑客,比如
import sys; sys.getfilesystemencoding = lambda: 'UTF-8'
import locale; locale.getpreferredencoding = lambda: 'utf-8'
在启动python解释器之前,我尝试设置pythonionecoding=utf8
环境变量
然而,这些都不起作用。唯一的解决方法是将编码明确指定为open
命令的命令行参数。这适用于上面的代码段,但它不会为我使用的所有软件包设置系统范围的默认值(这将以ASCII格式隐式打开文件,可能会也可能不会为我提供覆盖默认行为的方法)
设置python解释器默认文件系统编码的正确方法是什么?(当然不需要安装不必要的系统范围语言环境。)您可以设置
LC\u ALL
环境变量来更改默认值:
$ python3 -c 'import locale; print(locale.getpreferredencoding())'
UTF-8
$ LC_ALL='.ASCII' python3 -c 'import locale; print(locale.getpreferredencoding())'
US-ASCII
我在OSX和CentOS7上都进行了测试
至于您的其他尝试,以下是它们不起作用的原因:
仅适用于文件名(例如sys.getfilesystemencoding()
和好友)os.listdir()
模块实际上没有使用io
函数,因此更改模块上的函数不会产生效果。而是使用了一个轻量级的。下面将详细介绍locale.getpreferredencoding()
仅适用于PYTHONIOENCODING
、sys.stdin
和sys.stdout
sys.stdsterr
\u bootlocale
模块:
import _bootlocale
old = _bootlocale.getpreferredencoding # so you can restore
_bootlocale.getpreferredencoding = lambda *args: 'UTF-8'
这对我来说很有用(同样在OS X和CentOS 7上,使用3.6进行了测试):
为什么不直接使用
open('test.txt','r',encoding='utf8')
?显式比隐式好。不要使用黑客。sys.getfilesystemencoding()
不用于确定新打开文件的编码。替换locale.getpreferredencoding
不起作用,因为打开文件的C代码不会调用Python版本,它可以直接访问原始C函数。PYTHONIOENCODING
适用于stdin
,stdout
和stderr
,而不是open()
。为什么不在运行Python时使用LC_ALL='.UTF-8'
?您不需要设置整个区域设置,只要环境变量就足够了。@MartijnPieters我指出,添加encoding='utf8'
选项对代码段有效。但它不适用于我导入的所有包,也不适用于在内部打开文件的所有包。我需要将LC_CTYPE
设置为.UTF-8
,而不需要显式设置(因为Yocto Linux发行版默认情况下不安装区域设置)。我的问题是关于Intel Edison的。这是一个嵌入式系统,具有可定制的最小Linux系统,缺少macOS X和桌面Linux发行版所具有的许多功能。特别是,没有安装区域设置,因此设置LC.*
只会导致错误消息:-sh:warning:setlocale:LC.\u ALL:无法更改区域设置(.UTF-8):没有这样的文件或目录
@user8472:但这只是一个警告。Python工作吗?Python解释器的输出总是ANSI_X3.4-1968
,而不管LC_ALL
环境变量的内容如何。同样,解释器中的open
命令总是失败,除非我显式地将编码设置为'utf-8'
。我包含的包中的open
命令也会重复失败,而不管环境变量LC\u ALL
的值是多少。@user8472:这太糟糕了。这仅仅表明,在打开文件时,您永远不应该依赖于区域设置,并且无论何时您想要读取非ASCII的文本数据,都必须使用encoding='…'
。然而,我发现了io
模块真正使用的钩子,请参阅更新。是的,这很有效!对于我的代码(我同意我应该显式指定编码)和导入的代码(我没有控制权,可能无法显式指定编码)。
>>> 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'