csv - que - winrar online
py3k: ¿Cómo se lee un archivo dentro de un archivo zip como texto, no como bytes? (3)
Un sencillo programa para leer un archivo CSV dentro de un archivo zip funciona en Python 2.7, pero no 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?)
Entonces, el módulo csv
en Python 3 quiere ver un archivo de texto, pero zipfile.ZipFile.open
devuelve un zipfile.ZipExtFile
que siempre se trata como datos binarios.
¿Cómo hace esto que funcione en Python 3?
Me di cuenta de que la respuesta de Lennart no funcionaba con Python 3.1 , pero funciona con Python 3.2 . Han mejorado zipfile.ZipExtFile
en Python 3.2 (ver notas de la versión ). Estos cambios parecen hacer que zipfile.ZipExtFile
funcione bien con io.TextWrapper
.
Dicho sea de paso, funciona en Python 3.1, si descomenta las líneas hacky a continuación, en mono-patch zipfile.ZipExtFile
, no es que yo recomendaría este tipo de hackers. Lo incluyo solo para ilustrar la esencia de lo que se hizo en Python 3.2 para que todo funcione 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 tuviera que admitir py3k <3.2, me gustaría ir con la solución en mi otra respuesta .
Puede envolverlo en un io.TextIOWrapper .
items_file = io.TextIOWrapper(items_file, encoding=''your-encoding'', newline='''')
Deberia trabajar.
La respuesta de Lennart está en el camino correcto (gracias, Lennart, voté su respuesta) y casi funciona:
$ 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
El problema parece ser que el primer parámetro requerido de io.TextIOWrapper es un búfer ; no es un objeto de archivo
Esto parece funcionar:
items_file = io.TextIOWrapper(io.BytesIO(items_file.read()))
Esto parece un poco complejo y también parece molesto tener que leer en un archivo zip completo (tal vez enorme) en la memoria. ¿Alguna mejor manera?
Aquí está en acción:
$ 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