首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么TextIOWrapper要关闭给定的BytesIO流?

为什么TextIOWrapper要关闭给定的BytesIO流?
EN

Stack Overflow用户
提问于 2018-01-25 09:50:36
回答 1查看 2.7K关注 0票数 4

如果我在python3中运行以下代码

代码语言:javascript
复制
from io import BytesIO
import csv
from io import TextIOWrapper


def fill_into_stringio(input_io):
    writer = csv.DictWriter(TextIOWrapper(input_io, encoding='utf-8'),fieldnames=['ids'])
    for i in range(100):
        writer.writerow({'ids': str(i)})

with BytesIO() as input_i:
    fill_into_stringio(input_i)
    input_i.seek(0)

我得到一个错误:

代码语言:javascript
复制
ValueError: I/O operation on closed file.

而如果我不使用TextIOWrapper,io流将保持打开状态。例如,如果我将我的函数修改为

代码语言:javascript
复制
def fill_into_stringio(input_io):
    for i in range(100):
        input_io.write(b'erwfewfwef')

我再也没有收到任何错误,所以出于某种原因,TestIOWrapper关闭了我稍后要读取的流。这是这样的吗?是否如此?有没有办法在不亲自编写csv编写器的情况下实现我正在尝试的目标?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-01-25 10:09:39

csv模块是这里最奇怪的一个模块;包装其他对象的大多数类似文件的对象都承担了相关对象的所有权,当它们本身被关闭(或以其他方式清除)时将其关闭。

避免该问题的一种方法是在允许清理TextIOWrapper之前显式地从它执行detach

代码语言:javascript
复制
def fill_into_stringio(input_io):
    # write_through=True prevents TextIOWrapper from buffering internally;
    # you could replace it with explicit flushes, but you want something 
    # to ensure nothing is left in the TextIOWrapper when you detach
    text_input = TextIOWrapper(input_io, encoding='utf-8', write_through=True)
    try:
        writer = csv.DictWriter(text_input, fieldnames=['ids'])
        for i in range(100):
            writer.writerow({'ids': str(i)})
    finally:
        text_input.detach()  # Detaches input_io so it won't be closed when text_input cleaned up

另一种避免这种情况的内置方法是真正的文件对象,在这种情况下,您可以向它们传递文件描述符和closefd=False,并且在close-ed或其他清理时,它们不会关闭底层文件描述符。

当然,在您的特定情况下,还有一种更简单的方法:只需让您的函数期望基于文本的类似文件的对象,并在不重新包装的情况下使用它们;您的函数实际上不应该负责对调用者的输出文件进行编码(如果调用者想要UTF-16输出呢?)。

然后您可以执行以下操作:

代码语言:javascript
复制
from io import StringIO

def fill_into_stringio(input_io):
    writer = csv.DictWriter(input_io, fieldnames=['ids'])
    for i in range(100):
        writer.writerow({'ids': str(i)})

# newline='' is the Python 3 way to prevent line-ending translation
# while continuing to operate as text, and it's recommended for any file
# used with the csv module
with StringIO(newline='') as input_i:
    fill_into_stringio(input_i)
    input_i.seek(0)
    # If you really need UTF-8 bytes as output, you can make a BytesIO at this point with:
    # BytesIO(input_i.getvalue().encode('utf-8'))
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48434423

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档