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