web-dev-qa-db-fra.com

Comment puis-je utiliser io.StringIO () avec le module csv?

J'ai essayé de rétroporter un programme Python 3 en 2.7, et je suis coincé avec un étrange problème:

>>> import io
>>> import csv
>>> output = io.StringIO()
>>> output.write("Hello!")            # Fail: io.StringIO expects Unicode
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unicode argument expected, got 'str'
>>> output.write(u"Hello!")           # This works as expected.
6L
>>> writer = csv.writer(output)       # Now let's try this with the csv module:
>>> csvdata = [u"Hello", u"Goodbye"]  # Look ma, all Unicode! (?)
>>> writer.writerow(csvdata)          # Sadly, no.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unicode argument expected, got 'str'

Selon les documents, io.StringIO() renvoie un flux en mémoire pour le texte Unicode. Cela fonctionne correctement lorsque j'essaie de lui fournir manuellement une chaîne Unicode. Pourquoi échoue-t-il en conjonction avec le module csv, même si toutes les chaînes en cours d'écriture sont des chaînes Unicode? D'où provient le str qui provoque l'exception?

(Je sais que je peux utiliser StringIO.StringIO() à la place, mais je me demande ce qui ne va pas avec io.StringIO() dans ce scénario)

47
Tim Pietzcker

Le module Python 2.7 csv ne prend pas en charge l'entrée Unicode: voir le remarque au début de la documentation .

Il semble que vous devrez encoder les chaînes Unicode en chaînes d'octets et utiliser io.BytesIO, au lieu de io.StringIO.

La section exemples de la documentation inclut des exemples pour les classes wrapper UnicodeReader et UnicodeWriter (merci @AlexeyKachayev pour le pointeur).

49
Pedro Romano

Veuillez utiliser StringIO.StringIO ().

http://docs.python.org/library/io.html#io.StringIO

http://docs.python.org/library/stringio.html

io.StringIO est une classe. Il gère Unicode. Il reflète la structure de bibliothèque préférée Python 3.

StringIO.StringIO est une classe. Il gère les cordes. Il reflète l'héritage Python 2 structure de bibliothèque.

23
ernest

J'ai trouvé cela lorsque j'ai essayé de servir un fichier CSV via Flask directement sans créer le fichier CSV sur le système de fichiers. Cela fonctionne:

import io
import csv

data = [[u'cell one', u'cell two'], [u'cell three', u'cell four']]

output = io.BytesIO()
writer = csv.writer(output, delimiter=',')
writer.writerows(data)
your_csv_string = output.getvalue()

Voir également

7
Martin Thoma

Depuis la documentation de csv:

Le module csv ne prend pas directement en charge la lecture et l'écriture d'Unicode, mais il est propre à 8 bits, sauf pour certains problèmes avec les caractères ASCII NUL. Vous pouvez donc écrire des fonctions ou des classes qui gèrent l'encodage et le décodage pour vous aussi longtemps que vous évitez les encodages comme UTF-16 qui utilisent des NUL. UTF-8 est recommandé.

Vous pouvez trouver un exemple de UnicodeReader, UnicodeWriter ici http://docs.python.org/2/library/csv.html

4
Alexey Kachayev

Pour utiliser le lecteur/enregistreur CSV avec des "fichiers mémoire" dans python 2.7:

from io import BytesIO
import csv

csv_data = """a,b,c
foo,bar,foo"""

# creates and stores your csv data into a file the csv reader can read (bytes)
memory_file_in = BytesIO(csv_data.encode(encoding='utf-8'))

# classic reader
reader = csv.DictReader(memory_file_in)

# writes a csv file
fieldnames = reader.fieldnames  # here we use the data from the above csv file
memory_file_out = BytesIO()     # create a memory file (bytes)

# classic writer (here we copy the first file in the second file)
writer = csv.DictWriter(memory_file_out, fieldnames)
for row in reader:
    print(row)
    writer.writerow(row)
0
pangur