Yan*_*mer 4 python csv bytesio python-3.x
如果我在 python 3 中运行以下代码
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)
Run Code Online (Sandbox Code Playgroud)
我收到一个错误:
ValueError: I/O operation on closed file.
Run Code Online (Sandbox Code Playgroud)
如果我不使用 TextIOWrapper,io 流将保持打开状态。例如,如果我将函数修改为
def fill_into_stringio(input_io):
for i in range(100):
input_io.write(b'erwfewfwef')
Run Code Online (Sandbox Code Playgroud)
我不再收到任何错误,因此出于某种原因,TestIOWrapper 正在关闭我想稍后阅读的流。这是打算像这样吗,是否有一种方法可以在不自己编写 csv 编写器的情况下实现我的尝试?
这里的csv模块很奇怪;大多数包装其他对象的类文件对象都拥有相关对象的所有权,当它们自己关闭(或以其他方式清理)时将其关闭。
避免该问题的一种方法是明确detach从TextIOWrapper允许它被清理之前:
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
Run Code Online (Sandbox Code Playgroud)
避免这种情况的唯一其他内置方法是针对真实文件对象,您可以向它们传递文件描述符,closefd=False并且在close-ed 或以其他方式清除时它们不会关闭底层文件描述符。
当然,在您的特定情况下,有更简单的方法:只需让您的函数期望基于文本的类文件对象,并在不重新包装的情况下使用它们;你的函数真的不应该负责对调用者的输出文件进行编码(如果调用者想要 UTF-16 输出怎么办?)。
然后你可以这样做:
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'))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2449 次 |
| 最近记录: |