python3:将二进制文件写入标准输出缓冲区

2024-10-04 11:30:52 发布

您现在位置:Python中文网/ 问答频道 /正文

存在一个问题How to write binary data to stdout in python 3?,但所有的答案都表明sys.stdout.buffer或其变体(例如,手动重写文件描述符),它们有一个问题:它们不尊重缓冲:

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

有没有一种方法可以将二进制数据写入stdout,同时考虑到sys.stdout和未加修饰的print语句的缓冲?(实际的用例是,我有一个未知编码的“类似文本”的数据,我只想把它直接传递给stdout,而不必对特定的编码作出承诺。)


Tags: to数据pytest编码bufferstdoutsys
2条回答

您可以定义一个名为_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")

请参见:

你不能用flush交错调用write吗?你知道吗

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

相关问题 更多 >