zipfile — Acceso a archivos ZIP¶
Propósito: | Lee y escribe archivos ZIP. |
---|
El módulo zipfile
se puede usar para manipular archivos comprimidos ZIP, el
formato popularizado por el programa de PC PKZIP.
Probar archivos ZIP¶
La función is_zipfile()
devuelve un valor booleano que indica si o no el
nombre de archivo pasado como argumento se refiere a un archivo ZIP válido.
import zipfile
for filename in ['README.txt', 'example.zip',
'bad_example.zip', 'notthere.zip']:
print('{:>15} {}'.format(
filename, zipfile.is_zipfile(filename)))
Si el archivo no existe, is_zipfile()
devuelve False
.
$ python3 zipfile_is_zipfile.py
README.txt False
example.zip True
bad_example.zip False
notthere.zip False
Leer metadatos de un archivo¶
Usa la clase ZipFile
para trabajar directamente con un archivo ZIP. Éste
admite métodos para leer datos sobre archivos existentes, así como modificar
los archivos agregando archivos adicionales.
import zipfile
with zipfile.ZipFile('example.zip', 'r') as zf:
print(zf.namelist())
El método namelist()
devuelve los nombres de los archivos en un archivo
existente.
$ python3 zipfile_namelist.py
['README.txt']
Sin embargo, la lista de nombres es solo una parte de la información disponible
en el archivo. Para acceder a todos los metadatos sobre los contenidos del ZIP
usa los métodos infolist()
o getinfo()
.
import datetime
import zipfile
def print_info(archive_name):
with zipfile.ZipFile(archive_name) as zf:
for info in zf.infolist():
print(info.filename)
print(' Comment :', info.comment)
mod_date = datetime.datetime(*info.date_time)
print(' Modified :', mod_date)
if info.create_system == 0:
system = 'Windows'
elif info.create_system == 3:
system = 'Unix'
else:
system = 'UNKNOWN'
print(' System :', system)
print(' ZIP version :', info.create_version)
print(' Compressed :', info.compress_size, 'bytes')
print(' Uncompressed:', info.file_size, 'bytes')
print()
if __name__ == '__main__':
print_info('example.zip')
Hay campos adicionales distintos a los impresos aquí, pero descifrar los valores en algo útil requiere una lectura cuidadosa de la Nota de aplicación PKZIP con la especificación del archivo ZIP.
$ python3 zipfile_infolist.py
README.txt
Comment : b''
Modified : 2010-11-15 06:48:02
System : Unix
ZIP version : 30
Compressed : 65 bytes
Uncompressed: 76 bytes
Si el nombre del miembro del archivo es conocido de antemano, su objeto
ZipInfo
se puede recuperar directamente con getinfo()
.
import zipfile
with zipfile.ZipFile('example.zip') as zf:
for filename in ['README.txt', 'notthere.txt']:
try:
info = zf.getinfo(filename)
except KeyError:
print('ERROR: Did not find {} in zip file'.format(
filename))
else:
print('{} is {} bytes'.format(
info.filename, info.file_size))
Si el miembro del archivo no está presente, getinfo()
levanta un
KeyError
.
$ python3 zipfile_getinfo.py
README.txt is 76 bytes
ERROR: Did not find notthere.txt in zip file
Extraer archivos de un archivo¶
Para acceder a los datos de un miembro del archivo, usa el método read()
,
pasando el nombre del miembro.
import zipfile
with zipfile.ZipFile('example.zip') as zf:
for filename in ['README.txt', 'notthere.txt']:
try:
data = zf.read(filename)
except KeyError:
print('ERROR: Did not find {} in zip file'.format(
filename))
else:
print(filename, ':')
print(data)
print()
Los datos se descomprimen automáticamente, si es necesario.
$ python3 zipfile_read.py
README.txt :
b'The examples for the zipfile module use \nthis file and exampl
e.zip as data.\n'
ERROR: Did not find notthere.txt in zip file
Crear nuevos aRchivos¶
Para crear un archivo nuevo, crea una instancia de ZipFile
con un modo de
'w'
. Cualquier archivo existente se trunca y un nuevo archivo se empieza.
Para agregar archivos, usa el método write()
.
from zipfile_infolist import print_info
import zipfile
print('creating archive')
with zipfile.ZipFile('write.zip', mode='w') as zf:
print('adding README.txt')
zf.write('README.txt')
print()
print_info('write.zip')
Por defecto, el contenido del archivo no es comprimido.
$ python3 zipfile_write.py
creating archive
adding README.txt
README.txt
Comment : b''
Modified : 2016-08-07 13:31:24
System : Unix
ZIP version : 20
Compressed : 76 bytes
Uncompressed: 76 bytes
Para agregar compresión, se requiere el módulo zlib
. Si :mod: zlib
está disponible, el modo de compresión para archivos individuales o para el el
archivo en su conjunto se puede configurar usando zipfile.ZIP_DEFLATED
. El
modo de compresión predeterminado es zipfile.ZIP_STORED
, que agrega los
datos de entrada al archivo sin comprimirlos.
from zipfile_infolist import print_info
import zipfile
try:
import zlib
compression = zipfile.ZIP_DEFLATED
except (ImportError, AttributeError):
compression = zipfile.ZIP_STORED
modes = {
zipfile.ZIP_DEFLATED: 'deflated',
zipfile.ZIP_STORED: 'stored',
}
print('creating archive')
with zipfile.ZipFile('write_compression.zip', mode='w') as zf:
mode_name = modes[compression]
print('adding README.txt with compression mode', mode_name)
zf.write('README.txt', compress_type=compression)
print()
print_info('write_compression.zip')
Esta vez, el miembro del archivo es comprimido.
$ python3 zipfile_write_compression.py
creating archive
adding README.txt with compression mode deflated
README.txt
Comment : b''
Modified : 2016-08-07 13:31:24
System : Unix
ZIP version : 20
Compressed : 65 bytes
Uncompressed: 76 bytes
Usar nombres alternativos de miembros del archivo¶
Pasa un valor arcname
a write()
para agregar un archivo a un archivo
usando un nombre que no sea el nombre original del archivo.
from zipfile_infolist import print_info
import zipfile
with zipfile.ZipFile('write_arcname.zip', mode='w') as zf:
zf.write('README.txt', arcname='NOT_README.txt')
print_info('write_arcname.zip')
No hay ninguna señal del nombre de archivo original en el archivo.
$ python3 zipfile_write_arcname.py
NOT_README.txt
Comment : b''
Modified : 2016-08-07 13:31:24
System : Unix
ZIP version : 20
Compressed : 76 bytes
Uncompressed: 76 bytes
Escribir datos de fuentes que no sean archivos¶
A veces es necesario escribir en un archivo ZIP usando datos que no vienen de
un archivo existente. En lugar de escribir los datos a un archivo, luego
agregar ese archivo al archivo ZIP, usa el método writestr()
para agregar
una cadena de bytes directamente al archivo.
from zipfile_infolist import print_info
import zipfile
msg = 'This data did not exist in a file.'
with zipfile.ZipFile('writestr.zip',
mode='w',
compression=zipfile.ZIP_DEFLATED,
) as zf:
zf.writestr('from_string.txt', msg)
print_info('writestr.zip')
with zipfile.ZipFile('writestr.zip', 'r') as zf:
print(zf.read('from_string.txt'))
En este caso, el argumento compress_type
para ZipFile
es utilizado para
comprimir los datos, ya que writestr()
no toma un argumento para
especificar la compresión.
$ python3 zipfile_writestr.py
from_string.txt
Comment : b''
Modified : 2016-12-29 12:14:42
System : Unix
ZIP version : 20
Compressed : 36 bytes
Uncompressed: 34 bytes
b'This data did not exist in a file.'
Escribir con una instancia de ZipInfo¶
Normalmente, la fecha de modificación se calcula cuando un archivo o cadena es
añadido al archivo. Una instancia ZipInfo
se puede pasar a writestr()
para definir la fecha de modificación y otros metadatos.
import time
import zipfile
from zipfile_infolist import print_info
msg = b'This data did not exist in a file.'
with zipfile.ZipFile('writestr_zipinfo.zip',
mode='w',
) as zf:
info = zipfile.ZipInfo('from_string.txt',
date_time=time.localtime(time.time()),
)
info.compress_type = zipfile.ZIP_DEFLATED
info.comment = b'Remarks go here'
info.create_system = 0
zf.writestr(info, msg)
print_info('writestr_zipinfo.zip')
En este ejemplo, la hora de modificación se establece en la hora actual, los
datos se comprimen y se usa el valor falso para create_system
. Un simple
comentario también se asocia con el nuevo archivo.
$ python3 zipfile_writestr_zipinfo.py
from_string.txt
Comment : b'Remarks go here'
Modified : 2016-12-29 12:14:42
System : Windows
ZIP version : 20
Compressed : 36 bytes
Uncompressed: 34 bytes
Anexar a archivos¶
Además de crear nuevos archivos, es posible adjuntar a un archivo existente o
agregar un archivo al final de un archivo existente (como un archivo .exe
a
un archivo autoextraíble). Para abrir un archivo para adjuntarlo, usa el modo
'a'
.
from zipfile_infolist import print_info
import zipfile
print('creating archive')
with zipfile.ZipFile('append.zip', mode='w') as zf:
zf.write('README.txt')
print()
print_info('append.zip')
print('appending to the archive')
with zipfile.ZipFile('append.zip', mode='a') as zf:
zf.write('README.txt', arcname='README2.txt')
print()
print_info('append.zip')
El archivo resultante contiene dos miembros:
$ python3 zipfile_append.py
creating archive
README.txt
Comment : b''
Modified : 2016-08-07 13:31:24
System : Unix
ZIP version : 20
Compressed : 76 bytes
Uncompressed: 76 bytes
appending to the archive
README.txt
Comment : b''
Modified : 2016-08-07 13:31:24
System : Unix
ZIP version : 20
Compressed : 76 bytes
Uncompressed: 76 bytes
README2.txt
Comment : b''
Modified : 2016-08-07 13:31:24
System : Unix
ZIP version : 20
Compressed : 76 bytes
Uncompressed: 76 bytes
Archivos ZIP de Python¶
Python puede importar módulos desde dentro de archivos ZIP usando
zipimport
, si esos archivos aparecen en sys.path
. La clase
PyZipFile
se puede usar para construir un módulo adecuado para su uso de
esta manera. El método extra writepy()
le dice a PyZipFile
que escanee
un directorio en busca de archivos .py
y agrege el archivo .pyo
o
.pyc
correspondiente al archivo. Si ninguna forma compilada existe, se
crea y agrega un archivo .pyc
.
import sys
import zipfile
if __name__ == '__main__':
with zipfile.PyZipFile('pyzipfile.zip', mode='w') as zf:
zf.debug = 3
print('Adding python files')
zf.writepy('.')
for name in zf.namelist():
print(name)
print()
sys.path.insert(0, 'pyzipfile.zip')
import zipfile_pyzipfile
print('Imported from:', zipfile_pyzipfile.__file__)
Con el atributo de depuración de PyZipFile
establecido en 3
, la
depuración verbosa está habilitada y la salida se produce a medida que se
compila cada archivo .py
que se encuentra.
$ python3 zipfile_pyzipfile.py
Adding python files
Adding files from directory .
Compiling ./zipfile_append.py
Adding zipfile_append.pyc
Compiling ./zipfile_getinfo.py
Adding zipfile_getinfo.pyc
Compiling ./zipfile_infolist.py
Adding zipfile_infolist.pyc
Compiling ./zipfile_is_zipfile.py
Adding zipfile_is_zipfile.pyc
Compiling ./zipfile_namelist.py
Adding zipfile_namelist.pyc
Compiling ./zipfile_printdir.py
Adding zipfile_printdir.pyc
Compiling ./zipfile_pyzipfile.py
Adding zipfile_pyzipfile.pyc
Compiling ./zipfile_read.py
Adding zipfile_read.pyc
Compiling ./zipfile_write.py
Adding zipfile_write.pyc
Compiling ./zipfile_write_arcname.py
Adding zipfile_write_arcname.pyc
Compiling ./zipfile_write_compression.py
Adding zipfile_write_compression.pyc
Compiling ./zipfile_writestr.py
Adding zipfile_writestr.pyc
Compiling ./zipfile_writestr_zipinfo.py
Adding zipfile_writestr_zipinfo.pyc
zipfile_append.pyc
zipfile_getinfo.pyc
zipfile_infolist.pyc
zipfile_is_zipfile.pyc
zipfile_namelist.pyc
zipfile_printdir.pyc
zipfile_pyzipfile.pyc
zipfile_read.pyc
zipfile_write.pyc
zipfile_write_arcname.pyc
zipfile_write_compression.pyc
zipfile_writestr.pyc
zipfile_writestr_zipinfo.pyc
Imported from: pyzipfile.zip/zipfile_pyzipfile.pyc
Limitaciones¶
El módulo zipfile
no admite archivos ZIP con comentarios anexados, o
archivos multi-disco. Soporta archivos ZIP más grandes de 4 GB que utilizan
las extensiones ZIP64.
Ver también
- Documentación de la biblioteca estándar para zipfile
zlib
– Biblioteca de compresión ZIPtarfile
– Leer y escribir archivos tarszipimport
– Importar módulos de Python desde archivos ZIP- Nota de aplicación PKZIP – Especificación oficial del formato de archivo ZIP. archive format.