Python DictWriter 写入 UTF-8 编码的 CSV 文件
- 我有一个包含 Unicode 字符串的字典列表。
csv.DictWriter
可以把字典列表写入一个 CSV 文件。- 我希望这个 CSV 文件使用 UTF8 编码。
- 但是,
csv
模块不能把 Unicode 字符串转换成 UTF8。 在
csv
模块的文档中,有一个示例说明如何把所有内容转换成 UTF8:def utf_8_encoder(unicode_csv_data): for line in unicode_csv_data: yield line.encode('utf-8')
它还有一个
UnicodeWriter
类。
但是……我该怎么让 DictWriter
和这些一起工作呢?难道它们不需要在中间插入自己,以便在写入文件之前捕捉到被拆分的字典并进行编码吗?我不太明白。
6 个回答
15
你可以在把字典传给 DictWriter.writerow()
的时候,实时将值转换成 UTF-8 格式。比如说:
import csv
rows = [
{'name': u'Anton\xedn Dvo\u0159\xe1k','country': u'\u010cesko'},
{'name': u'Bj\xf6rk Gu\xf0mundsd\xf3ttir', 'country': u'\xcdsland'},
{'name': u'S\xf8ren Kierkeg\xe5rd', 'country': u'Danmark'}
]
# implement this wrapper on 2.6 or lower if you need to output a header
class DictWriterEx(csv.DictWriter):
def writeheader(self):
header = dict(zip(self.fieldnames, self.fieldnames))
self.writerow(header)
out = open('foo.csv', 'wb')
writer = DictWriterEx(out, fieldnames=['name','country'])
# DictWriter.writeheader() was added in 2.7 (use class above for <= 2.6)
writer.writeheader()
for row in rows:
writer.writerow(dict((k, v.encode('utf-8')) for k, v in row.iteritems()))
out.close()
输出的文件叫 foo.csv:
name,country
Antonín Dvořák,Česko
Björk Guðmundsdóttir,Ísland
Søren Kierkegård,Danmark
41
有一个简单的方法可以解决这个问题,使用很棒的UnicodeCSV模块。安装好这个模块后,只需要把这一行
import csv
改成
import unicodecsv as csv
这样就能自动很好地支持UTF-8编码了。
注意:如果你切换到Python 3,这个问题也会消失(感谢jamescampbell的建议)。而且其实切换到Python 3是个很好的选择。
101
更新: 第三方的 unicodecsv 模块已经实现了这个七年前的解决方案。下面的代码就是个例子。此外,还有一个不需要第三方模块的 Python 3 解决方案。
原始 Python 2 的回答
如果你使用的是 Python 2.7 或更高版本,可以用字典推导式把字典转换成 utf-8 格式,然后再传给 DictWriter:
# coding: utf-8
import csv
D = {'name':u'马克','pinyin':u'mǎkè'}
f = open('out.csv','wb')
f.write(u'\ufeff'.encode('utf8')) # BOM (optional...Excel needs it to open UTF-8 file properly)
w = csv.DictWriter(f,sorted(D.keys()))
w.writeheader()
w.writerow({k:v.encode('utf8') for k,v in D.items()})
f.close()
你可以用这个思路把 UnicodeWriter 更新为 DictUnicodeWriter:
# coding: utf-8
import csv
import cStringIO
import codecs
class DictUnicodeWriter(object):
def __init__(self, f, fieldnames, dialect=csv.excel, encoding="utf-8", **kwds):
# Redirect output to a queue
self.queue = cStringIO.StringIO()
self.writer = csv.DictWriter(self.queue, fieldnames, dialect=dialect, **kwds)
self.stream = f
self.encoder = codecs.getincrementalencoder(encoding)()
def writerow(self, D):
self.writer.writerow({k:v.encode("utf-8") for k,v in D.items()})
# 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 D in rows:
self.writerow(D)
def writeheader(self):
self.writer.writeheader()
D1 = {'name':u'马克','pinyin':u'Mǎkè'}
D2 = {'name':u'美国','pinyin':u'Měiguó'}
f = open('out.csv','wb')
f.write(u'\ufeff'.encode('utf8')) # BOM (optional...Excel needs it to open UTF-8 file properly)
w = DictUnicodeWriter(f,sorted(D.keys()))
w.writeheader()
w.writerows([D1,D2])
f.close()
Python 2 unicodecsv 示例:
# coding: utf-8
import unicodecsv as csv
D = {u'name':u'马克',u'pinyin':u'mǎkè'}
with open('out.csv','wb') as f:
w = csv.DictWriter(f,fieldnames=sorted(D.keys()),encoding='utf-8-sig')
w.writeheader()
w.writerow(D)
Python 3:
另外,Python 3 自带的 csv 模块本身就支持 Unicode 格式:
# coding: utf-8
import csv
D = {u'name':u'马克',u'pinyin':u'mǎkè'}
# Use newline='' instead of 'wb' in Python 3.
with open('out.csv','w',encoding='utf-8-sig',newline='') as f:
w = csv.DictWriter(f,fieldnames=sorted(D.keys()))
w.writeheader()
w.writerow(D)