Python 3:将二进制写入标准输出,同时注意缓冲

时间:2019-04-15 01:11:13

标签: python

存在一个问题How to write binary data to stdout in python 3?,但所有答案都建议sys.stdout.buffer或其变体(例如,手动重新包装文件描述符),但有一个问题:它们不考虑缓冲:< / p>

MacBook-Pro-116:~ ezyang$ cat test.py
import sys
sys.stdout.write("A")
sys.stdout.buffer.write(b"B")
MacBook-Pro-116:~ ezyang$ python3 test.py | cat
BA

是否有一种方法可以在尊重sys.stdout和未经修饰的print语句的缓冲的同时将二进制数据写入stdout? (实际的用例是,我有一个未知编码的“类似文本”的数据,我只想直接将其传递给stdout而不承诺使用特定的编码。)

2 个答案:

答案 0 :(得分:0)

您可以定义一个名为_print的局部函数(甚至可以通过命名print来覆盖系统print函数),如下所示:

import sys

def _print(data):
    """
    If data is bytes, write to stdout using sys.stdout.buffer.write,
    otherwise, assume it's str and convert to bytes with utf-8
    encoding before writing.
    """
    if type(data) != bytes:
        data = bytes(data, 'utf-8')
    sys.stdout.buffer.write(data)

_print('A')
_print(b'B')

输出应为AB

注意:通常,系统print函数将换行符添加到输出中。上面的_print仅输出数据(bytes或假设其为str)而没有换行符。

缓冲实现

如果要缓冲的I / O,可以使用io库中的工具进行管理。

简单的例子:

import io
import sys

output_buffer = None
text_wrapper = None

def init_buffer():
    global output_buffer, text_wrapper
    if not output_buffer:
        output_buffer = io.BytesIO()
        text_wrapper = io.TextIOWrapper(
            output_buffer,
            encoding='utf-8',
            write_through=True)

def write(data):
    if type(data) == bytes:
        output_buffer.write(data)
    else:
        text_wrapper.write(data)

def flush():
    sys.stdout.buffer.write(output_buffer.getvalue())

# initialize buffer, write some data, and then flush to stdout
init_buffer()
write("A")
write(b"B")
write("foo")
write(b"bar")
flush()

例如,如果要执行某个函数中的所有输出写操作,则可以使用contextlib.contextmanager创建一个工厂函数,该函数可以使用with ...语句:

# This uses the vars and functions in the example above.

import contextlib

@contextlib.contextmanager
def buffered_stdout():
    """
    Create a factory function for using the `with` statement
    to write to the output buffer.
    """
    global output_buffer
    init_buffer()
    fh = sys.stdout.buffer
    try:
        yield fh
    finally:
        try:
            fh.write(output_buffer.getvalue())
        except AttributeError:
            pass


# open the buffered output stream and write some data to it
with buffered_stdout():
    write("A")
    write(b"B")
    write("foo")
    write(b"bar")

请参阅:

答案 1 :(得分:0)

您不能将对write的呼叫与flush进行交错吗?

sys.stdout.write("A")

sys.stdout.buffer.write(b"B")

结果:

  

BA


sys.stdout.write("A")
sys.stdout.flush()

sys.stdout.buffer.write(b"B")
sys.stdout.flush()

结果:

  

AB