Can I pipe a io.BytesIO() stream to subprocess.popen() in Python?

删除回忆录丶 提交于 2020-03-14 06:58:16

问题


I'm trying to pipe a io.BytesIO() bytetream to a separate program using subprocess.popen(), but I don't know how or if this is at all possible. Documentation and examples are all about text and newlines.

When I whip up something like this:

import io
from subprocess import *

stream = io.BytesIO()
someStreamCreatingProcess(stream)

command = ['somecommand', 'some', 'arguments']  
process = Popen(command, stdin=PIPE)
process.communicate(input=stream)

I get

Traceback (most recent call last):
  File "./test.py", line 9, in <module>
    procOut         = process.communicate(input=stream)
  File "/usr/lib/python2.7/subprocess.py", line 754, in communicate
    return self._communicate(input)
  File "/usr/lib/python2.7/subprocess.py", line 1322, in _communicate
    stdout, stderr = self._communicate_with_poll(input)
  File "/usr/lib/python2.7/subprocess.py", line 1384, in _communicate_with_poll
    chunk = input[input_offset : input_offset + _PIPE_BUF]
TypeError: '_io.BytesIO' object has no attribute '__getitem__'

I think popen() is only for text. Am I wrong?
Is there a different way to do this?


回答1:


As @falsetru said you can't stream BytesIO() object directly; you need to get a bytestring from it first. It implies that all content should be already written to stream before you call stream.getvalue() to pass to process.communicate().

If you want to stream instead of providing all input at once then you could drop BytesIO() object and write to the pipe directly:

from subprocess import Popen, PIPE

process = Popen(['command', 'arg1'], stdin=PIPE, bufsize=-1)
someStreamCreatingProcess(stream=process.stdin) # many `stream.write()` inside
process.stdin.close() # done (no more input)
process.wait()

someStreamCreatingProcess() should not return until it is done writing to the stream. If it returns immediately then it should call stream.close() at some point in the future (remove process.stdin.close() in your code):

from subprocess import Popen, PIPE

process = Popen(['command', 'arg1'], stdin=PIPE, bufsize=-1)
someStreamCreatingProcess(stream=process.stdin) # many `stream.write()` inside
process.wait() # stream.close() is called in `someStreamCreatingProcess`



回答2:


According to subprocess.Popen.communicate:

The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.


To get (bytes) string value from BytesIO object, use getvalue:

process.communicate(input=stream.getvalue())


来源:https://stackoverflow.com/questions/20321116/can-i-pipe-a-io-bytesio-stream-to-subprocess-popen-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!