2010-06-21 10 views
17

Je ne peux pas créer un utf-8 fichier csv en Python.Créer un utf-8 fichier csv en Python

Je suis en train de lire est docs, et dans le examples section, il dit:

For all other encodings the following UnicodeReader and UnicodeWriter classes can be used. They take an additional encoding parameter in their constructor and make sure that the data passes the real reader or writer encoded as UTF-8:

Ok. J'ai donc ce code:

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

Et je continue à obtenir cette erreur:

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) 

Quelqu'un peut-il s'il vous plaît me donner une lumière pour que je puisse comprendre ce que l'enfer que je fais mal depuis que je mets tous les codage partout avant d'appeler la classe 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) 
+0

:) Il Seens le problème est avec le codecs.open. Quand je l'enlève et que j'utilise simplement ouvert, ça marche. Pourquoi? –

Répondre

14

Vous ne devez pas utiliser codecs.open; UnicodeWriter prend l'entrée Unicode et prend soin de tout encoder en UTF-8. Lorsque UnicodeWriter écrit dans le gestionnaire de fichiers que vous lui avez transmis, tout est déjà en codage UTF-8 (par conséquent, il fonctionne avec un fichier normal que vous avez ouvert avec open).

En utilisant codecs.open, vous convertir essentiellement vos objets Unicode UTF-8 chaînes dans UnicodeWriter, puis essayez de ré-encoder ces chaînes à nouveau en UTF-8 comme si ces chaînes contiennent des chaînes Unicode, ce qui évidemment échoue.

+0

Comment ai-je essayé d'encoder deux fois, puisque je viens d'ouvrir un objet fichier? Codec.open ne vient pas d'ouvrir un flux d'objet fichier indiquant son encodage? –

+2

Selon les docs de 'codecs.open':" Ouvrir un fichier encodé en utilisant le mode donné et renvoyer une version encapsulée * fournissant un encodage/décodage transparent *. ". En d'autres termes, si vous ouvrez un fichier pour l'écriture avec 'codecs.open', il va tout d'abord coder tout ce que vous avez écrit en UTF-8. –

+0

Je pensais que «fournir un encodage/décodage transparent» était trop subjectif. Je pense que si j'ai besoin de comprendre plus je dois juste lire la source. –

0

Vous n'avez pas besoin de "tout coder".

Votre application devrait fonctionner entièrement en Unicode.

Est-ce que l'encodage seulement dans le codecs.open d'écrire UTF-8 octets dans un fichier externe. Ne faites aucun autre encodage dans votre application.

+1

Le module Csv ne fonctionne pas avec unicode. Pour que mon code fonctionne, je dois supprimer exactement le codecs.open. –

+0

Si CSV ne fonctionne pas avec unicode, vous ne pouvez pas l'utiliser pour créer UTF-8, sauf si vous voulez écrire votre propre codeur UTF-8. –

1

Comme vous l'avez compris, il fonctionne si vous utilisez plaine.

La raison est que vous avez essayé de coder UTF-8 deux fois. Une fois dans

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

, puis plus tard dans UnicodeWriter.writeRow

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

Pour vérifier que cela fonctionne utiliser votre code d'origine et outcomment cette ligne.

Greetz

Questions connexes