在 python3 中写入 csv 中的 io.BytesIO 失败
Posted
技术标签:
【中文标题】在 python3 中写入 csv 中的 io.BytesIO 失败【英文标题】:Writing to io.BytesIO in csv fails in python3 【发布时间】:2016-10-24 18:13:43 【问题描述】:我正在尝试编写兼容 python 2/3 的代码来将字符串写入 csv 文件对象。这段代码:
line_as_list = [line.encode() for line in line_as_list]
writer_file = io.BytesIO()
writer = csv.writer(writer_file, dialect=dialect, delimiter=self.delimiter)
for line in line_as_list:
assert isinstance(line,bytes)
writer.writerow(line)
在 Python3 上出现此错误:
> writer.writerow(line)
E TypeError: a bytes-like object is required, not 'str'
但是assert类型没有问题,那为什么csv
会报错呢?
我不能只对 Python 2 和 3 使用 BytesIO
吗?问题出在哪里?
【问题讨论】:
@tdelaney 我的意思是我不确定 StringIO 和 BytesIO 是否会为源文本提供相同的表示形式(可能在utf-8
中)。这就是我尝试使用相同的输出对象类型的原因。
【参考方案1】:
在 Python3 中,csv.writer
期望以文本模式打开一个类似文件的对象。
在 Python2 中,csv.writer
期望以二进制模式打开类似文件的对象。
因此,在Python3中使用io.StringIO
,而在Python2中使用io.BytesIO
:
import io
import csv
import sys
PY3 = sys.version_info[0] == 3
line_as_list = [u'foo', u'bar']
encoding = 'utf-8'
if PY3:
writer_file = io.StringIO()
else:
writer_file = io.BytesIO()
line_as_list = [line.encode(encoding) for line in line_as_list]
writer = csv.writer(writer_file, dialect='excel', delimiter=',')
writer.writerow(line_as_list)
content = writer_file.getvalue()
if PY3:
content = content.encode(encoding)
print(type(content))
print(repr(content))
在 Python3 中,上面的代码打印出来
<class 'bytes'>
b'foo,bar\r\n'
在 Python2 中,上面的代码打印出来
<type 'str'>
'foo,bar\r\n'
【讨论】:
这是一个很好的解决方法,但知道为什么当 str is 是字节格式时错误要求输入“字节”吗? 我相信错误来自BytesIO
对象——它抱怨它在预期bytes
时传递了str
。在 Python3 中,str
不是“字节格式”。一个 unicode str
是一个代码点序列。
但是我传递了一个 str.encode() 对象,实际上是一个字节对象。那么问题出在哪里?此错误表示 str
已通过,但未通过(仅谈论 Python 3)。
我无法重现您发布的错误,所以这只是一个猜测。 self.delimiter
是什么?会不会是str
?
是的,可能是这样,尽管在对分隔符进行编码后,它说“分隔符必须是字符串,而不是字节”。以上是关于在 python3 中写入 csv 中的 io.BytesIO 失败的主要内容,如果未能解决你的问题,请参考以下文章
使用writer.writerows(reader)在python3中逐个编写csv行而不是一次写入csv行