py3k: Comment lire un fichier dans un fichier zip sous forme de texte et non d'octets?
un programme simple pour lire un fichier CSV à l'intérieur d'un fichier zip fonctionne en python 2.7, mais pas en Python 3.2
$ cat test_zip_file_py3k.py
import csv, sys, zipfile
zip_file = zipfile.ZipFile(sys.argv[1])
items_file = zip_file.open('items.csv', 'rU')
for row in csv.DictReader(items_file):
pass
$ python2.7 test_zip_file_py3k.py ~/data.zip
$ python3.2 test_zip_file_py3k.py ~/data.zip
Traceback (most recent call last):
File "test_zip_file_py3k.py", line 8, in <module>
for row in csv.DictReader(items_file):
File "/home/msabramo/run/lib/python3.2/csv.py", line 109, in __next__
self.fieldnames
File "/home/msabramo/run/lib/python3.2/csv.py", line 96, in fieldnames
self._fieldnames = next(self.reader)
_csv.Error: iterator should return strings, not bytes (did you open the file
in text mode?)
donc le module csv
en Python 3 veut voir un fichier texte, mais zipfile.ZipFile.open
renvoie un zipfile.ZipExtFile
qui est toujours traité comme des données binaires.
Comment faire pour que cela fonctionne en Python 3?
3 réponses
je viens de remarquer que réponse de Lennart n'a pas fonctionné avec Python 3.1 , mais il ne travailler avec Python 3.2 . Ils ont amélioré zipfile.ZipExtFile
en Python 3.2 (voir release notes ). Ces changements semblent faire en sorte que zipfile.ZipExtFile
fonctionne bien avec io.TextWrapper
.
Soit dit en passant, cela fonctionne en python 3.1, si vous décommentez les lignes hacky ci-dessous à Monkey-patch zipfile.ZipExtFile
, non pas que je recommande ce genre de hackery. Je l'inclus seulement pour illustrer l'essence de ce qui a été fait en Python 3.2 Pour faire les choses fonctionnent bien.
$ cat test_zip_file_py3k.py
import csv, io, sys, zipfile
zip_file = zipfile.ZipFile(sys.argv[1])
items_file = zip_file.open('items.csv', 'rU')
# items_file.readable = lambda: True
# items_file.writable = lambda: False
# items_file.seekable = lambda: False
# items_file.read1 = items_file.read
items_file = io.TextIOWrapper(items_file)
for idx, row in enumerate(csv.DictReader(items_file)):
print('Processing row {0} -- row = {1}'.format(idx, row))
si je devais soutenir py3k < 3.2, alors j'irais avec la solution dans mon autre réponse .
Vous pouvez l'envelopper dans un io.TextIOWrapper .
items_file = io.TextIOWrapper(items_file, encoding='your-encoding', newline='')
devrait marcher.
la réponse de Lennart est sur la bonne voie (merci, Lennart, j'ai voté votre réponse) et il presque travaux:
$ cat test_zip_file_py3k.py
import csv, io, sys, zipfile
zip_file = zipfile.ZipFile(sys.argv[1])
items_file = zip_file.open('items.csv', 'rU')
items_file = io.TextIOWrapper(items_file, encoding='iso-8859-1', newline='')
for idx, row in enumerate(csv.DictReader(items_file)):
print('Processing row {0}'.format(idx))
$ python3.1 test_zip_file_py3k.py ~/data.zip
Traceback (most recent call last):
File "test_zip_file_py3k.py", line 7, in <module>
items_file = io.TextIOWrapper(items_file,
encoding='iso-8859-1',
newline='')
AttributeError: readable
Le problème semble être que io.Le premier paramètre requis de TextWrapper est un buffer ; pas un objet de fichier.
Cela semble fonctionner:
items_file = io.TextIOWrapper(io.BytesIO(items_file.read()))
Cela semble un peu complexe, et aussi il cela semble ennuyeux d'avoir à lire dans un fichier zip entier (peut-être énorme) dans la mémoire. Une meilleure façon?
Ici, on est dans l'action:
$ cat test_zip_file_py3k.py
import csv, io, sys, zipfile
zip_file = zipfile.ZipFile(sys.argv[1])
items_file = zip_file.open('items.csv', 'rU')
items_file = io.TextIOWrapper(io.BytesIO(items_file.read()))
for idx, row in enumerate(csv.DictReader(items_file)):
print('Processing row {0}'.format(idx))
$ python3.1 test_zip_file_py3k.py ~/data.zip
Processing row 0
Processing row 1
Processing row 2
...
Processing row 250