在 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 失败的主要内容,如果未能解决你的问题,请参考以下文章

python3 写入CSV出现空白行问题

python3 写入CSV出现空白行问题

使用writer.writerows(reader)在python3中逐个编写csv行而不是一次写入csv行

Python 3.3 CSV.Writer 写入额外的空白行

[python3]csv 模块用法

将 Python3 中的数据帧写入 Netezza