![](/img/trans.png)
[英]Can I pipe a io.BytesIO() stream to subprocess.popen() in Python?
[英]Can I set Python 3.5 subprocess.Popen pipe encoding?
我有一個小問題。 我的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')
幾個旁注:
Popen
時顯式設置bufsize
是正確的,因為如果不這樣做,就不可能在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
功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.