58

我试图将 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()在这种情况下有什么问题)

4

5 回答 5

55

Python 2.7csv模块不支持 Unicode 输入:请参阅文档开头的注释

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

文档的示例部分包括 aUnicodeReaderUnicodeWriter包装类的示例(感谢 @AlexeyKachayev 提供的指针)。

于 2012-10-29T10:56:37.713 回答
24

请使用 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 库结构。

于 2013-10-08T08:56:05.937 回答
14

当我尝试直接通过 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()

也可以看看

于 2017-08-10T08:34:06.993 回答
4

csv文档:

csv 模块不直接支持读写 Unicode,但它是 8-bit-clean 保存 ASCII NUL 字符的一些问题。因此,只要您避免使用像 UTF-16 这样使用 NUL 的编码,您就可以编写函数或类来为您处理编码和解码。推荐使用 UTF-8。

您可以在此处找到UnicodeReaderhttp://docs.python.org/2/library/csv.htmlUnicodeWriter示例

于 2012-10-29T11:00:55.530 回答
1

在 python 2.7 中使用带有“内存文件”的 CSV 读取器/写入器:

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)
于 2019-06-14T14:15:29.140 回答