2010-06-21 23 views
17

No puedo crear un archivo utf-8 csv en Python.Crear un archivo utf-8 csv en Python

Estoy intentando leer su documentación, y en el examples section, que 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. Así que tengo este código:

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

Y sigo recibiendo este error:

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) 

Puede alguien por favor, dame una luz así que puedo entender qué demonios estoy haciendo mal desde que puse toda la codificación en todas partes antes de llamar a la clase 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

Se seens el problema es con los codecs.open. Cuando lo elimino y simplemente uso abierto, funciona. ¿Por qué? –

Respuesta

14

No tiene que usar codecs.open; UnicodeWriter toma la entrada Unicode y se encarga de codificar todo en UTF-8. Cuando UnicodeWriter escribe en el identificador de archivo que le pasó, todo está ya en codificación UTF-8 (por lo tanto, funciona con un archivo normal que abrió con open).

Mediante el uso de codecs.open, que esencialmente convertir sus objetos Unicode UTF-8 cuerdas en UnicodeWriter, a continuación, intente volver a codificar estas cadenas en UTF-8 de nuevo, como si estas cadenas contenían cadenas Unicode, lo que falla obviamente.

+0

¿Cómo exactamente intenté codificar dos veces, ya que acabo de abrir un objeto de archivo? ¿Codec.open no acaba de abrir una secuencia de objeto de archivo que indique su codificación? –

+2

De acuerdo con los documentos de 'codecs.open':" Abra un archivo codificado usando el modo dado y devuelva una versión envolvente * que proporcione una codificación/decodificación transparente *. ". En otras palabras, si abre un archivo para escribir con 'codecs.open', codificará de forma transparente todo lo que escriba en el UTF-8 primero. –

+0

Pensé que "proporcionar codificación/decodificación transparentes" era demasiado subjetivo. Creo que si necesito entender más, solo tengo que leer la fuente. –

0

No es necesario "codificar doblemente" todo.

Su aplicación debería funcionar completamente en Unicode.

Realice la codificación solo en codecs.open para escribir bytes UTF-8 en un archivo externo. No haga otra codificación dentro de su aplicación.

+1

El módulo Csv no funciona con Unicode. Para hacer que mi código funcione, tengo que eliminar exactamente el codecs.open. –

+0

Si CSV no funciona con Unicode, entonces no puede usarlo para crear UTF-8, a menos que desee escribir su propio codificador UTF-8. –

1

Como has descubierto, funciona si utilizas la apertura simple.

La razón de esto es que trataste de codificar UTF-8 dos veces. Una vez en

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

y luego más tarde en UnicodeWriter.writeRow

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

Para comprobar que esto funciona usan el código original y outcomment esa línea.

Greetz