为什么用 universal_newlines 打开子进程会导致 unicode 解码异常?
Why does opening a subprocess with universal_newlines cause a unicode decode exception?
我正在使用子进程模块 运行 子作业,并使用 subprocess.PIPE 收集其输出和错误流。为了避免死锁,我不断地在一个单独的线程上读取这些流。这有效,除了有时程序由于解码问题而崩溃:
`UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 483: ordinal not in range(128
在高层次上,我知道 Python 可能正在尝试使用 ASCII 编解码器转换为字符串,并且我需要在某处调用解码,我只是不确定在哪里。当我创建我的子进程作业时,我将 universal_newlines 指定为 True。我认为这意味着 return stdout/stderr 作为 unicode,而不是二进制:
self.p = subprocess.Popen(self.command, shell=self.shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
崩溃发生在我的阅读线程函数中:
def standardOutHandler(standardOut):
# Crash happens on the following line:
for line in iter(standardOut.readline, ''):
writerLock.acquire()
stdout_file.write(line)
if self.echoOutput:
sys.stdout.write(line)
sys.stdout.flush()
writerLock.release()
不清楚为什么readline会在这里抛出解码异常;正如我所说,我认为 universal_newlines 为真已经 return 给我解码数据。
这是怎么回事,我该如何纠正?
这是完整的回溯
Exception in thread Thread-5:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/threading.py", line 920, in _bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/threading.py", line 868, in run
self._target(*self._args, **self._kwargs)
File "/Users/lzrd/my_process.py", line 61, in standardOutHandler
for line in iter(standardOut.readline, ''):
File "/Users/lzrd/Envs/my_env/bin/../lib/python3.4/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 483: ordinal not in range(128)
如果您使用 universal_newlines=True
,则字节流将使用 locale.getpreferredencoding(False)
字符编码解码为 Unicode,在您的系统上应该是 utf-8
(检查 LANG
、LC_CTYPE
、LC_ALL
环境变量)。
如果异常仍然存在;用一个空循环体试试你的代码:
for line in standardOut: #NOTE: no need to use iter() idiom here on Python 3
pass
如果你仍然遇到异常,那么它可能是 Python 中的错误,如果 locale.getpreferredencoding(False)
不是 ascii
如果你在 Popen()
调用附近检查它 - 它在这里使用完全相同的环境很重要。
如果 UnicodeDecodeError
显示的是 utf-8
而不是 ascii
,我会理解。在这种情况下,您可以尝试手动解码流:
#!/usr/bin/env python3
import io
import locale
from subprocess import Popen, PIPE
with Popen(['command', 'arg 1'], stdout=PIPE, bufsize=1) as p:
for line in io.TextIOWrapper(p.stdout,
encoding=locale.getpreferredencoding(False),
errors='strict'):
print(line, end='')
您可以在此处试验 encoding
、errors
参数,例如,设置 encoding='ascii'
或使用 errors='namereplace'
将不支持的字符(在给定的字符编码中)替换为 \N{...}
转义序列(用于调试)。
maby 很好:
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, encoding='utf-8')
out, err = process.communicate()
print('out: ')
print(out)
print('err: ')
print(err)
我正在使用子进程模块 运行 子作业,并使用 subprocess.PIPE 收集其输出和错误流。为了避免死锁,我不断地在一个单独的线程上读取这些流。这有效,除了有时程序由于解码问题而崩溃:
`UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 483: ordinal not in range(128
在高层次上,我知道 Python 可能正在尝试使用 ASCII 编解码器转换为字符串,并且我需要在某处调用解码,我只是不确定在哪里。当我创建我的子进程作业时,我将 universal_newlines 指定为 True。我认为这意味着 return stdout/stderr 作为 unicode,而不是二进制:
self.p = subprocess.Popen(self.command, shell=self.shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
崩溃发生在我的阅读线程函数中:
def standardOutHandler(standardOut):
# Crash happens on the following line:
for line in iter(standardOut.readline, ''):
writerLock.acquire()
stdout_file.write(line)
if self.echoOutput:
sys.stdout.write(line)
sys.stdout.flush()
writerLock.release()
不清楚为什么readline会在这里抛出解码异常;正如我所说,我认为 universal_newlines 为真已经 return 给我解码数据。
这是怎么回事,我该如何纠正?
这是完整的回溯
Exception in thread Thread-5:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/threading.py", line 920, in _bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/threading.py", line 868, in run
self._target(*self._args, **self._kwargs)
File "/Users/lzrd/my_process.py", line 61, in standardOutHandler
for line in iter(standardOut.readline, ''):
File "/Users/lzrd/Envs/my_env/bin/../lib/python3.4/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 483: ordinal not in range(128)
如果您使用 universal_newlines=True
,则字节流将使用 locale.getpreferredencoding(False)
字符编码解码为 Unicode,在您的系统上应该是 utf-8
(检查 LANG
、LC_CTYPE
、LC_ALL
环境变量)。
如果异常仍然存在;用一个空循环体试试你的代码:
for line in standardOut: #NOTE: no need to use iter() idiom here on Python 3
pass
如果你仍然遇到异常,那么它可能是 Python 中的错误,如果 locale.getpreferredencoding(False)
不是 ascii
如果你在 Popen()
调用附近检查它 - 它在这里使用完全相同的环境很重要。
如果 UnicodeDecodeError
显示的是 utf-8
而不是 ascii
,我会理解。在这种情况下,您可以尝试手动解码流:
#!/usr/bin/env python3
import io
import locale
from subprocess import Popen, PIPE
with Popen(['command', 'arg 1'], stdout=PIPE, bufsize=1) as p:
for line in io.TextIOWrapper(p.stdout,
encoding=locale.getpreferredencoding(False),
errors='strict'):
print(line, end='')
您可以在此处试验 encoding
、errors
参数,例如,设置 encoding='ascii'
或使用 errors='namereplace'
将不支持的字符(在给定的字符编码中)替换为 \N{...}
转义序列(用于调试)。
maby 很好:
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, encoding='utf-8')
out, err = process.communicate()
print('out: ')
print(out)
print('err: ')
print(err)