我可以设置Python 3.5 subprocess.Popen管道编码吗?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我可以设置Python 3.5 subprocess.Popen管道编码吗?相关的知识,希望对你有一定的参考价值。
我有一个边缘案例问题。我的Python script_A.py有这段代码(缩写)。
script_A.py:
from __future__ import unicode_literals
import subprocess
executable = 'sample.exe'
kwargs['bufsize'] = 0
kwargs['executable'] = executable
kwargs['stdin'] = subprocess.PIPE
kwargs['stdout'] = subprocess.PIPE
kwargs['stderr'] = subprocess.PIPE
kwargs['preexec_fn'] = None
kwargs['close_fds'] = False
kwargs['shell'] = False
kwargs['cwd'] = None
kwargs['env'] = None
kwargs['universal_newlines'] = True
kwargs['startupinfo'] = None
kwargs['creationflags'] = 0
if sys.version_info.major == 3 and sys.version_info.minor > 5:
kwargs['encoding'] = 'utf-8'
args = ['', '-x']
subproc = subprocess.Popen(args, **kwargs)
# service subproc.stdout and subproc.stderr on threads
stdout = _start_thread(_get_stdout, subproc)
stderr = _start_thread(_get_stderr, subproc)
with codecs.open('myutf-8.txt', encoding='utf-8') as fh:
for line in fh:
if os.name == 'nt':
subproc.stdin.write(b'%s\n' % line.rstrip().encode('utf-8'))
else:
subproc.stdin.write('%s\n' % line.rstrip()) # OFFENDING LINE BELOW
stdout.join()
此代码始终适用于Windows 8/10和Ubuntu 16.04 / 17.10上的Python 2.7.14和3.6.4。请注意,某些kwargs值在Windows上是不同的,但它们在这里无关紧要。它适用于16.04上的Python 3.5.2,但仅限于我从Gnome终端执行script_A.py时。
有时,我需要使用script_B.py来启动script_A.py而不是终端。 Script_B.py具有相同的subprocess.Popen()代码,用于启动相应的Python可执行文件。
script_B.py
if os.name == 'nt':
if use_py2:
executable = 'C:\\Python27\\python.exe'
else:
executable = 'C:\\Program Files\\Python36\\python.exe'
else:
if use_py2:
executable = '/usr/bin/python'
else:
executable = '/usr/bin/python3'
args = ['', 'script_A.py']
# ---- ditto above code from here ----
当我在Python 3.5.2上使用Popen()从script_B.py执行script_A.py时出现此错误。 OS / Python版本的其他组合都没有失败。
Traceback:
File "script_A.py", line 30, in run
subproc.stdin.write('%s\n' % line.rstrip())
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)
您可以在2.7.14和3.6.4中看到,我使用特定代码强制管道为utf-8。我不知道如何在3.5.2上设置utf-8编码。
那么,有没有办法在3.5.2 Popen的管道上配置编码?从支持中排除Python 3.5可能更容易,但我想我会问这里。
您的输入文件是UTF-8,并且您要提供数据的程序需要UTF-8输入。所以直接发送原始二进制文件,而不是从字节到文本解码,然后从文本重新编码到字节。
摆脱打开universal_newlines
模式的线,以及设置kwargs['encoding']
的线,并替换为with
提供的整个stdin
块:
blinesep = os.linesep.encode('utf-8') # Since you seem to need OS specific line endings
with open('myutf-8.txt', 'rb') as fh:
for line in fh:
subproc.stdin.writelines((sline, blinesep))
如果你愿意,你仍然可以将stdout
/ stderr
流作为文本流处理,你只需用io.TextIOWrapper
和相应的编码明确地包装它们。例如,您可以使用以下内容包装二进制stdout
:
textout = io.TextIOWrapper(subproc.stdout, encoding='utf-8')
几个附注:
- 你在调用
bufsize
时显式设置Popen
是正确的,因为如果没有这样做,就不可能在Python版本中表现一致;默认缓冲行为在Python 2和Python 3.3.0及更早版本上是无缓冲的(bufsize=0
),在3.3.1及更高版本中是-1
(意思是“使用合适的默认缓冲区大小”)。为了表现,明确使用bufsize=-1
是一个好主意;无论如何你都在线程读取,所以缓冲死锁不是一个问题。 - 切勿使用
codecs.open
。这是错误的(不翻译行结尾,混合readline
与read(n)
调用做奇怪的事情,当没有编码通过,它甚至不包括普通open
的结果,所以API改变等),慢,和准弃用。如果您需要在Python 2.6及更高版本上保持一致的行为,请使用io.open
,它在Python 2.6及更高版本上提供Python 3内置的open
函数。
以上是关于我可以设置Python 3.5 subprocess.Popen管道编码吗?的主要内容,如果未能解决你的问题,请参考以下文章
执行外部命令subproces.run,subproces.Popen()
如何使用 Python 2.7 创建 Python 3.5 虚拟环境?