如何在csv模块中使用io.StringIO()?

时间:2012-10-29 10:47:29

标签: python csv unicode python-2.7

我试图将Python 3程序向后移植到2.7,我遇到了一个奇怪的问题:

>>> import io
>>> import csv
>>> output = io.StringIO()
>>> output.write("Hello!")            # Fail: io.StringIO expects Unicode
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unicode argument expected, got 'str'
>>> output.write(u"Hello!")           # This works as expected.
6L
>>> writer = csv.writer(output)       # Now let's try this with the csv module:
>>> csvdata = [u"Hello", u"Goodbye"]  # Look ma, all Unicode! (?)
>>> writer.writerow(csvdata)          # Sadly, no.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unicode argument expected, got 'str'

根据文档,io.StringIO()返回Unicode文本的内存中流。当我尝试手动输入Unicode字符串时,它可以正常工作。为什么它与csv模块一起失败,即使写入的所有字符串都是Unicode字符串? str来自哪里会导致异常?

(我知道我可以使用StringIO.StringIO()代替,但我想知道在这种情况下io.StringIO()出了什么问题)

5 个答案:

答案 0 :(得分:47)

Python 2.7 csv模块不支持Unicode输入:请参阅note at the beginning of the documentation

您似乎必须将Unicode字符串编码为字节字符串,并使用io.BytesIO而不是io.StringIO

文档的examples部分包含UnicodeReaderUnicodeWriter包装类的示例(感谢@AlexeyKachayev指针)。

答案 1 :(得分:23)

请使用StringIO.StringIO()。

http://docs.python.org/library/io.html#io.StringIO

http://docs.python.org/library/stringio.html

io.StringIO是一个班级。它处理Unicode。它反映了首选的Python 3库结构。

StringIO.StringIO是一个班级。它处理字符串。它反映了遗留的Python 2库结构。

答案 2 :(得分:7)

当我尝试通过Flask直接提供CSV文件而不在文件系统上创建CSV文件时,我发现了这一点。这有效:

import io
import csv

data = [[u'cell one', u'cell two'], [u'cell three', u'cell four']]

output = io.BytesIO()
writer = csv.writer(output, delimiter=',')
writer.writerows(data)
your_csv_string = output.getvalue()

另见

答案 3 :(得分:4)

来自csv文档:

  

csv模块不直接支持读写Unicode,   但是对于ASCII NUL的一些问题,它是8位清除   字符。所以你可以编写处理函数的函数或类   只要你避免像编码一样编码和解码   使用NUL的UTF-16。建议使用UTF-8。

您可以在此处找到UnicodeReaderUnicodeWriter http://docs.python.org/2/library/csv.html

的示例

答案 4 :(得分:0)

要将CSV读/写器与python 2.7中的“内存文件”一起使用:

from io import BytesIO
import csv

csv_data = """a,b,c
foo,bar,foo"""

# creates and stores your csv data into a file the csv reader can read (bytes)
memory_file_in = BytesIO(csv_data.encode(encoding='utf-8'))

# classic reader
reader = csv.DictReader(memory_file_in)

# writes a csv file
fieldnames = reader.fieldnames  # here we use the data from the above csv file
memory_file_out = BytesIO()     # create a memory file (bytes)

# classic writer (here we copy the first file in the second file)
writer = csv.DictWriter(memory_file_out, fieldnames)
for row in reader:
    print(row)
    writer.writerow(row)