【问题标题】:Create an utf-8 csv file in Python在 Python 中创建一个 utf-8 csv 文件
【发布时间】:2010-06-21 13:58:24
【问题描述】:

我无法在 Python 中创建 utf-8 csv 文件。

我正在尝试阅读它的文档,在 examples section 中,它说:

对于所有其他编码,以下 UnicodeReader 和 UnicodeWriter 可以使用类。他们采取 在他们的附加编码参数 构造函数并确保 数据通过真正的读者或作者 编码为 UTF-8:

好的。所以我有这个代码:

values = (unicode("Ñ", "utf-8"), unicode("é", "utf-8"))
f = codecs.open('eggs.csv', 'w', encoding="utf-8")
writer = UnicodeWriter(f)
writer.writerow(values)

我不断收到此错误:

line 159, in writerow
    self.stream.write(data)
  File "/usr/lib/python2.6/codecs.py", line 686, in write
    return self.writer.write(data)
  File "/usr/lib/python2.6/codecs.py", line 351, in write
    data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 22: ordinal not in range(128)

有人可以给我一个灯,这样我就可以理解我到底做错了什么,因为我在调用 UnicodeWriter 类之前设置了所有的编码?

class UnicodeWriter:
    """
    A CSV writer which will write rows to CSV file "f",
    which is encoded in the given encoding.
    """

    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
        # Redirect output to a queue
        self.queue = cStringIO.StringIO()
        self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
        self.stream = f
        self.encoder = codecs.getincrementalencoder(encoding)()

    def writerow(self, row):
        self.writer.writerow([s.encode("utf-8") for s in row])
        # Fetch UTF-8 output from the queue ...
        data = self.queue.getvalue()
        data = data.decode("utf-8")
        # ... and reencode it into the target encoding
        data = self.encoder.encode(data)
        # write to the target stream
        self.stream.write(data)
        # empty queue
        self.queue.truncate(0)

    def writerows(self, rows):
        for row in rows:
            self.writerow(row)

【问题讨论】:

  • 发现问题出在 codecs.open 上。当我删除它并使用 open 时,它可以工作。为什么?

标签: python encoding utf-8 csv


【解决方案1】:

您不必使用codecs.openUnicodeWriter 接受 Unicode 输入并将所有内容编码为 UTF-8。当 UnicodeWriter 写入您传递给它的文件句柄时,所有内容都已采用 UTF-8 编码(因此它适用于您使用 open 打开的普通文件)。

通过使用codecs.open,您实际上将Unicode 对象转换为UnicodeWriter 中的UTF-8 字符串,然后尝试再次将这些字符串重新编码为UTF-8,就好像这些字符串包含Unicode 字符串一样,这显然失败了。

【讨论】:

  • 我究竟是如何尝试编码两次的,因为我刚刚打开了一个文件对象?不是 codec.open 只是打开了一个文件对象流,表明它正在编码吗?
  • 根据codecs.open 的文档:“使用给定模式打开编码文件并返回包装版本提供透明编码/解码。”。换句话说,如果您使用codecs.open 打开一个文件进行写入,它将首先透明地将您写入其中的所有内容编码为UTF-8。
  • 我认为“提供透明编码/解码”过于主观。我想如果我需要了解更多,我只需要阅读源代码。
【解决方案2】:

正如您所发现的,如果您使用普通打开,它会起作用。

原因是您尝试对 UTF-8 进行两次编码。一次进入

f = codecs.open('eggs.csv', 'w', encoding="utf-8")

然后在 UnicodeWriter.writeRow 中

# ... and reencode it into the target encoding
data = self.encoder.encode(data)

要检查这是否有效,请使用您的原始代码并注释该行。

问候

【讨论】:

    【解决方案3】:

    不久前我遇到了 csv / unicode 挑战,并将其扔到了 bitbucket 上:http://bitbucket.org/famousactress/dude_csv .. 可能对你有用,如果你的需求很简单 :)

    【讨论】:

      【解决方案4】:

      您不需要对所有内容进行“双重编码”。

      您的应用程序应该完全使用 Unicode。

      仅在codecs.open 中进行编码以将 UTF-8 字节写入外部文件。在您的应用程序中不要进行其他编码。

      【讨论】:

      • Csv 模块不适用于 unicode。为了使我的代码正常工作,我必须完全删除 codecs.open。
      • 如果 CSV 不能与 unicode 一起使用,那么您不能使用它来创建 UTF-8,除非您想编写自己的 UTF-8 编码器。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-24
      • 2019-03-13
      • 2015-02-13
      • 2018-07-26
      相关资源
      最近更新 更多