如何修改Python3中os.popen()的默认编码为UTF-8?
遇到一个编码问题,问题简化如下:
在当前 desktop 目录下,有如下内容:
desktop $ ls
client.py server.py 中文测试
arcpy.txt codetest.py test.py
如上所示有一个中文命名的文件 ----> 中文测试
# -*- coding:utf-8 -*-
# python3.5.1
import os,sys
print (sys.getdefaultencoding()) #系统默认编码
dir_list = os.listdir()
for li in dir_list:
print (li)
输出如下:
utf-8
arcpy.txt
client.py
codetest.py
server.py
test.py
中文测试
可以看出默认编码为 utf-8,os.listdir()命令可以正常输出中文字符。
在使用 os.popen()时:
# -*- coding:utf-8 -*-
# python3.5.1
import os,sys
print (sys.getdefaultencoding()) #系统默认编码
dir_list = os.popen(‘ls’,‘r’).read()
for li in dir_list:
print (li)
报错如下:
utf-8
Traceback (most recent call last):
File "Desktop/codetest.py", line 8, in <module>
dir_list = os.popen('ls','r').read()
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 76: ordinal not in range(128)
既虽然默认编码为‘ utf-8',但 popen()读取目录时,依旧采用 ascii 编码,无法输出中文。 请问该如何解决?
如何修改Python3中os.popen()的默认编码为UTF-8?
os.popen(‘ls’, 'rb).read()
出来一个 bytes 对象,然后 decode 一下
在Python 3中,os.popen()返回的是一个文件对象,其编码通常由系统区域设置决定。要修改其默认编码为UTF-8,最直接的方法是使用subprocess模块替代,因为它提供了更强大和清晰的编码控制。
例如,使用subprocess.run()并指定text=True和encoding='utf-8':
import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True, text=True, encoding='utf-8')
print(result.stdout)
如果你确实需要坚持使用os.popen(),可以通过解码和编码来手动处理:
import os
with os.popen('dir') as proc:
# 假设输出是系统默认编码,先按默认编码解码为字符串,再按需处理
# 但注意:在Windows上,os.popen()默认可能不是UTF-8,比如是gbk
raw_output = proc.read()
# 尝试用utf-8解码,如果失败则用系统默认编码(如gbk)
try:
decoded_output = raw_output.encode('utf-8').decode('utf-8')
except UnicodeDecodeError:
decoded_output = raw_output # 或者用其他编码如gbk解码
print(decoded_output)
但这种方法并不总是可靠,因为os.popen()的内部编码取决于系统和命令。更推荐使用subprocess模块,它更现代且支持直接指定编码。
总结:用subprocess替代os.popen()来明确控制编码。
3.6.5 在 MAC OSX 下没有问题
io 模块里有个可以 wrap 一下的。
os.popen 相当于 subprocess.Popen + io.TextIOWrapper,io.TextIOWrapper 默认使用的编码是 locale.getpreferredencoding(False)。
class io.TextIOWrapper(buffer, encoding=None, errors=None, newline=None, line_buffering=False, write_through=False)
A buffered text stream over a BufferedIOBase binary stream. It inherits TextIOBase.
encoding gives the name of the encoding that the stream will be decoded or encoded with. It defaults to locale.getpreferredencoding(False).
locale.getpreferredencoding(do_setlocale=True)
Return the encoding used for text data, according to user preferences. User preferences are expressed differently on different systems, and might not be available programmatically on some systems, so this function only returns a guess.
这个编码应该是由语言环境变量判断来的,在我这终端下( Mac OS )这个编码是 ‘UTF-8’,所以你的代码在我这可以正常运行。在你的运行环境中这个编码是 ‘ascii’,于是就出错了。
解决办法 1:改用 subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE),然后手动 decode(‘utf-8’)。
解决办法 2:尝试修改你的语言环境变量,使得 locale.getpreferredencoding 返回 ‘UTF-8’ 编码。
五楼正解,popen 出来的通道是和你的 shell 的编码一致的,要么 bytes 然后 decode.encode,要么就改 shell 的编码
终端下( Mac OS X ) python3.5.1 和 python3.6.4 同运行正常。但在 sublime Text 3 中结果就是解码错误。
Sublime Text 的 Build System 也是用 subprocess.Popen 来运行用户脚本的,在这种情况下因为不存在 LANG 环境变量,所以 locale.getpreferredencoding 返回的是 ‘US-ASCII’ 编码。
可以在 Build System 的配置文件 Python.sublime-build 中添加 LANG 变量来使其变为 ‘UTF-8’:
“env”: {“PYTHONIOENCODING”: “utf-8”, “LANG”: “en_US.UTF-8”}
参考:
https://stackoverflow.com/questions/42101759/how-to-change-the-preferred-encoding-in-sublime-text-3-for-macos
非常感谢您的回复。
在终端里
$locale
LANG="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_CTYPE="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_ALL=
LC_ALL 无默认值
$ python 3.5
>>> import locale
>>> locale.getpreferredencoding()
'UTF-8’
而在 sublime Text3 中
# python3.5
>>>import locale
>>>print (locale.getpreferredencoding())
US-ASCII
>>>print (locale.getdefaultlocale())
(None, None)
因为编码不同产生了错误。
您上面的回复是一种解决方式
还可以在代码中临时设置语言环境
>>>locale.setlocale(locale.LC_ALL,‘zh_CN.UTF-8’)
解决问题。
不过您的解决方式是一劳永逸的。
参考:
https://docs.python.org/2/library/locale.html#locale.getdefaultlocale
接下来去查查 sys.getdefaultencoding()与 locale.getdefaultlocale()的区别了~~~
os.popen(cmd).buffer.read().decode(encoding=‘utf8’)
不好意思,刚刚以为代码简化一行之后就没事了,后来发现还是图样
def exec(cmd:str):
pip = os.popen(cmd) # 这个地方不能合并一行写,会出错说 read of closed file
return pip.buffer.read().decode(encoding=‘utf8’)
#11 代码有帮助


