簡體   English   中英

我可以設置Python 3.5 subprocess.Popen管道編碼嗎?

[英]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')

幾個旁注:

  1. 您正確地在調用Popen時顯式設置bufsize是正確的,因為如果不這樣做,就不可能在Python版本之間保持一致的行為。 在Python 2和Python 3.3.0及更早版本中,默認緩沖行為是未緩沖( bufsize=0 ),而在3.3.1及更高版本中,默認緩沖行為是-1 (表示“使用適當的默認緩沖區大小”)。 為了提高性能,顯式使用bufsize=-1是個好主意; 您無論如何都要對讀取進行線程化,因此不必擔心緩沖死鎖。
  2. 切勿使用codecs.open 它是越野車(不轉換行結束,混合readlineread(n)調用不奇怪的事情,在沒有經過編碼,它甚至不換行的純結果open ,因此API的變化等),速度慢,並已過時。 如果您需要在python 2.6和更高版本上具有一致的行為,請使用io.open ,它在python 2.6或更高版本上提供一致的Python 3內置open功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM