首页 > 解决方案 > 使 Python 内置流包装器不关闭底层 BytesIO

问题描述

我正在创建内存文件作为io.BytesIO对象。

文件内容是使用顶部的各种内置 Python 包装器创建的,例如io.TextIOWrapperor csv.DictWriter(只是一个示例,我正在使用更多 Python 的 stdlib):

def generate_file():
    raw_bytes = io.BytesIO()
    with io.TextIOWrapper(raw_bytes, encoding='utf-8') as wrapper:
        writer = csv.DictWriter(wrapper, ["a", "b", "c"])
        writer.writeheader()
    return raw_bytes

这种方法失败了,因为TextIOWrapper将关闭其底层流 = our raw_bytes

generate_file().seek(0)

ValueError: I/O operation on closed file.

根据https://bugs.python.org/issue21363,可以分离缓冲区,但这也无济于事,因为上下文管理器会引发另一个错误:

def generate_file():
    raw_bytes = io.BytesIO()
    with io.TextIOWrapper(raw_bytes, encoding='utf-8') as wrapper:
        writer = csv.DictWriter(wrapper, ["a", "b", "c"])
        writer.writeheader()
        wrapper.detach()
    return raw_bytes

generate_file().seek(0)

ValueError: underlying buffer has been detached

我找到了两个解决方案:

  1. 部分破解:不要使用上下文管理器,然后上面的方法有效(上下文管理器不会尝试访问分离的对象)。

  2. 一般技巧:让 BytesIO 忽略任何close()调用:

class NonClosingBytesIO(io.BytesIO):

    def close(self):
        pass


def generate_file():
    raw_bytes = NonClosingBytesIO()
    with io.TextIOWrapper(raw_bytes, encoding='utf-8') as wrapper:
        writer = csv.DictWriter(wrapper, ["a", "b", "c"])
        writer.writeheader()
    return raw_bytes

generate_file().getvalue()

b'a,b,c\r\n'

问:这样安全吗?你能想出一个更好(更清洁)的解决方案吗?

标签: pythonpython-3.7

解决方案


推荐阅读