Python DictWriter编写UTF-8编码的CSV文件

  1. 我有一个包含unicodestring的字典列表。
  2. csv.DictWriter可以将一个字典列表写入一个CSV文件。
  3. 我希望CSV文件以UTF8编码。
  4. csv模块无法处理将unicodestring转换为UTF8。
  5. csv模块文档有一个将所有内容转换为UTF8的例子:

def utf_8_encoder(unicode_csv_data): for line in unicode_csv_data: yield line.encode('utf-8') 

它也有一个class UnicodeWriter:

但是…我如何让DictWriter与这些工作? 难道他们不得不在自己的中间注入自己的词汇,以便在将它们写入文件之前捕获反汇编的字典并对其进行编码? 我不明白。

如果使用Python 2.7或更高版本,请在传递给DictWriter之前使用dict理解将字典重新映射为utf-8:

 # 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() 

使用美妙的UnicodeCSV模块有一个简单的解决方法。 有了它,只要改变线路

 import csv 

 import unicodecsv as csv 

它自动地开始玩UTF-8。

当您将字典传递给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 

您可以根据需要使用一些代理类来编码字典值,如下所示:

 # -*- coding: utf-8 -*- import csv d = {'a':123,'b':456, 'c':u'Non-ASCII: проверка'} class DictUnicodeProxy(object): def __init__(self, d): self.d = d def __iter__(self): return self.d.__iter__() def get(self, item, default=None): i = self.d.get(item, default) if isinstance(i, unicode): return i.encode('utf-8') return i with open('some.csv', 'wb') as f: writer = csv.DictWriter(f, ['a', 'b', 'c']) writer.writerow(DictUnicodeProxy(d)) 

当你用你的内容调用csv.writer时,想法是通过utf_8_encoder传递内容,因为它会给你(utf-8)编码的内容。

我的解决scheme有点不同。 虽然上面的所有解决scheme都集中在具有Unicode兼容的字典,我的解决scheme使DictWriter兼容Unicode。 这个方法甚至在python文档( 1 )中提出。

类UTF8Recoder,UnicodeReader,UnicodeWriter取自python文档。 UnicodeWriter-> Writer也改变了一点。

用它作为普通的DictWriter / DictReader。

这里是代码:

 import csv, codecs, cStringIO class UTF8Recoder: """ Iterator that reads an encoded stream and reencodes the input to UTF-8 """ def __init__(self, f, encoding): self.reader = codecs.getreader(encoding)(f) def __iter__(self): return self def next(self): return self.reader.next().encode("utf-8") class UnicodeReader: """ A CSV reader which will iterate over lines in the CSV file "f", which is encoded in the given encoding. """ def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds): f = UTF8Recoder(f, encoding) self.reader = csv.reader(f, dialect=dialect, **kwds) def next(self): row = self.reader.next() return [unicode(s, "utf-8") for s in row] def __iter__(self): return self 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([unicode(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) class UnicodeDictWriter(csv.DictWriter, object): def __init__(self, f, fieldnames, restval="", extrasaction="raise", dialect="excel", *args, **kwds): super(UnicodeDictWriter, self).__init__(f, fieldnames, restval="", extrasaction="raise", dialect="excel", *args, **kwds) self.writer = UnicodeWriter(f, dialect, **kwds)