2010-06-21 14 views
17

Non riesco a creare un file csv utf-8 in Python.Creare un file csv utf-8 in Python

Sto cercando di leggere è documenti, e nel examples section, si dice:

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. Così ho questo codice:

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

E continuo a ricevere questo errore:

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) 

Per favore qualcuno può dare una luce così posso capire che cosa diavolo sto facendo male da quando ho messo tutto il codifica ovunque prima di chiamare 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

E seens il problema è con i codecs.open. Quando lo rimuovo e uso solo aperto, funziona. Perché? –

risposta

14

Non è necessario utilizzare codecs.open; UnicodeWriter accetta l'input Unicode e si occupa della codifica di tutto in UTF-8. Quando UnicodeWriter scrive nel gestore file passato, tutto è già nella codifica UTF-8 (quindi funziona con un normale file aperto con open).

Utilizzando codecs.open, è essenzialmente convertire i vostri oggetti Unicode UTF-8 stringhe in UnicodeWriter, quindi provare a ricodificare queste stringhe in UTF-8 di nuovo come se queste stringhe contengono stringhe Unicode, che non riesce ovviamente.

+0

In che modo ho provato a codificare due volte, poiché ho appena aperto un oggetto file? Non è codec.open appena aperto un flusso di file oggetto che indica che è la codifica? –

+2

Secondo i documenti di 'codecs.open':" Aprire un file codificato usando la modalità data e restituire una versione * incapsulata che fornisce codifica/decodifica trasparente *. ". In altre parole, se apri un file per scrivere con 'codecs.open', codificherà in modo trasparente tutto ciò che scrivi in ​​UTF-8 prima. –

+0

Ho pensato che "fornire codifica/decodifica trasparente" fosse troppo soggettivo. Penso che se ho bisogno di capire di più devo solo leggere la fonte. –

0

Non è necessario "duplicare" tutto.

L'applicazione dovrebbe funzionare interamente in Unicode.

Effettuare la codifica solo nello codecs.open per scrivere byte UTF-8 in un file esterno. Non fare altre codifiche all'interno della tua applicazione.

+1

Il modulo Csv non funziona con unicode. Per far funzionare il mio codice, devo rimuovere esattamente i codecs.open. –

+0

Se CSV non funziona con Unicode, non è possibile utilizzarlo per creare UTF-8, a meno che non si desideri scrivere il proprio codificatore UTF-8. –

1

Come hai capito, funziona se si utilizza semplicemente aperto.

Il motivo è che si è tentato di codificare UTF-8 due volte. Una volta in

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

e poi successivamente in UnicodeWriter.writeRow

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

Per verificare che funziona questa utilizzare il codice originale e outcomment quella linea.

Greetz