zipfile en Python: archivos ZIP seguros

Publicado el: 27/07/2026
Tempo de leitura: 5 minutos
Icono de archivo ZIP para un artículo sobre zipfile en Python

El módulo zipfile en Python forma parte de la biblioteca estándar y permite crear, leer, inspeccionar y extraer archivos ZIP sin instalar paquetes externos. Es útil para copias de seguridad, exportación de informes, distribución de documentos, procesamiento de cargas y automatizaciones que necesitan reunir muchos archivos en un único contenedor.

Aunque la API es sencilla, un flujo fiable debe controlar los nombres internos, el tamaño total, las entradas duplicadas, la integridad y las rutas de extracción. En esta guía aprenderás a usar ZipFile, elegir modos de apertura, escribir contenido en memoria, leer archivos sin extraer todo, inspeccionar metadatos y aplicar validaciones prácticas. El tema complementa otros recursos de la biblioteca estándar, como graphlib para dependencias, contextvars para contexto seguro, heapq para colas de prioridad y singledispatch para API extensibles.

Abrir un archivo ZIP

La clase principal es zipfile.ZipFile. El modo r abre un archivo existente para lectura, w crea o reemplaza, a agrega contenido y x crea un archivo nuevo y falla si el destino ya existe.

from zipfile import ZipFile

with ZipFile("datos.zip", "r") as archivo:
    print(archivo.namelist())

Conviene utilizar siempre un administrador de contexto. Los ZIP mantienen un directorio central con los metadatos de sus miembros y un archivo que no se cierra correctamente puede quedar incompleto.

Crear un paquete

Usa write() para añadir un archivo del disco. El argumento arcname define el nombre interno guardado en el ZIP.

from zipfile import ZIP_DEFLATED, ZipFile

with ZipFile("respaldo.zip", "w", compression=ZIP_DEFLATED) as archivo:
    archivo.write("informes/ventas.csv", arcname="ventas.csv")
    archivo.write("config/app.json", arcname="config/app.json")

Elige nombres internos cortos y portables. Evita rutas absolutas y directorios específicos del servidor porque dificultan el traslado del archivo y pueden revelar estructura local.

Escribir contenido en memoria

Cuando los datos ya existen como texto o bytes, writestr() evita crear un archivo temporal.

from zipfile import ZIP_DEFLATED, ZipFile

contenido = "id,nombre\n1,Ana\n2,Caio\n"
with ZipFile("exportacion.zip", "w", ZIP_DEFLATED) as archivo:
    archivo.writestr("clientes.csv", contenido)

Esta técnica funciona bien para informes pequeños generados bajo demanda. Para salidas grandes, utiliza archivos temporales o procesamiento por bloques para no conservar todo el resultado en memoria.

Leer sin extraer

El método read() devuelve un miembro como bytes. open() devuelve un objeto similar a un archivo y permite procesar el contenido de forma gradual.

from zipfile import ZipFile

with ZipFile("datos.zip") as archivo:
    with archivo.open("config.json") as entrada:
        texto = entrada.read().decode("utf-8")
        print(texto)

Esto es útil para enviar el contenido directamente a un analizador de JSON, CSV, XML o texto sin escribir otra copia en el disco.

Inspeccionar miembros

infolist() devuelve objetos ZipInfo con nombre, tamaño original, tamaño comprimido, fecha y método de compresión.

with ZipFile("carga.zip") as archivo:
    for item in archivo.infolist():
        print(item.filename, item.file_size, item.compress_size)

Revisa los metadatos antes de extraer. La aplicación puede rechazar extensiones no permitidas, demasiadas entradas, miembros demasiado grandes o relaciones de compresión poco habituales.

Validar rutas de extracción

El nombre de un miembro debe tratarse como entrada externa. Resuelve el destino final y comprueba que permanezca dentro del directorio autorizado.

from pathlib import Path
from zipfile import ZipFile

raiz = Path("recibidos").resolve()
with ZipFile("carga.zip") as archivo:
    for item in archivo.infolist():
        destino = (raiz / item.filename).resolve()
        if raiz not in destino.parents and destino != raiz:
            raise ValueError(f"Ruta inválida: {item.filename}")
        archivo.extract(item, raiz)

También conviene rechazar nombres absolutos, componentes innecesarios y tipos de archivo que la aplicación no necesite.

Aplicar límites de recursos

Un archivo comprimido pequeño puede expandirse hasta ocupar mucho más espacio. Define un máximo por miembro y otro para el paquete completo.

MAX_ARCHIVO = 50 * 1024 * 1024
MAX_TOTAL = 200 * 1024 * 1024

total = 0
for item in archivo.infolist():
    if item.file_size > MAX_ARCHIVO:
        raise ValueError("Miembro demasiado grande")
    total += item.file_size
    if total > MAX_TOTAL:
        raise ValueError("El paquete supera el límite total")

Cuenta también los bytes realmente copiados. Así la aplicación puede detenerse si los metadatos declarados no coinciden con el flujo procesado.

Comprobar integridad

testzip() lee los miembros y verifica su CRC. Devuelve el primer nombre con problemas o None cuando no encuentra errores.

from zipfile import BadZipFile, ZipFile

try:
    with ZipFile("archivo.zip") as archivo:
        dañado = archivo.testzip()
        if dañado:
            raise ValueError(f"Miembro dañado: {dañado}")
except BadZipFile:
    print("El archivo no es un ZIP válido")

En una API, registra los detalles técnicos internamente y devuelve al cliente un mensaje sencillo.

Elegir la compresión

ZIP_DEFLATED ofrece amplia compatibilidad y funciona bien con texto y datos estructurados. BZIP2 y LZMA pueden reducir más algunos contenidos, pero herramientas antiguas quizá no los soporten. Imágenes JPEG, vídeos y archivos ya comprimidos suelen mejorar poco.

El parámetro compresslevel controla el equilibrio entre velocidad y tamaño. Mide con datos reales antes de aumentar el nivel en tareas frecuentes.

Tratar nombres duplicados

Un ZIP puede contener varias entradas con el mismo nombre. Distintas herramientas pueden elegir entradas diferentes, por lo que conviene normalizar y registrar los nombres antes de extraer.

vistos = set()
for item in archivo.infolist():
    nombre = item.filename.replace("\\", "/").casefold()
    if nombre in vistos:
        raise ValueError(f"Nombre duplicado: {item.filename}")
    vistos.add(nombre)

Considera diferencias entre mayúsculas y minúsculas, tipos de barra y representaciones Unicode equivalentes.

Extracción controlada

Para archivos externos, inspecciona y copia un miembro cada vez. Esto permite aplicar límites, mostrar progreso y eliminar resultados parciales si ocurre un error.

import shutil

for item in archivo.infolist():
    destino = raiz / item.filename
    if item.is_dir():
        destino.mkdir(parents=True, exist_ok=True)
        continue
    destino.parent.mkdir(parents=True, exist_ok=True)
    with archivo.open(item) as origen, destino.open("wb") as salida:
        shutil.copyfileobj(origen, salida, length=1024 * 1024)

Archivos con contraseña

La biblioteca estándar puede leer algunos ZIP con cifrado tradicional, pero no es la mejor opción para requisitos modernos de confidencialidad. La información sensible necesita herramientas actuales, una gestión correcta de claves y un modelo de amenazas claro.

Pruebas importantes

Incluye pruebas para archivos vacíos, datos ZIP inválidos, nombres duplicados, directorios, nombres Unicode, miembros grandes, límites totales y rutas no permitidas. Comprueba también que los archivos parciales se eliminen después de una excepción.

Buenas prácticas

  • Usa with en todas las operaciones.
  • Define nombres internos con arcname.
  • Valida la ruta final antes de escribir.
  • Limita cantidad de miembros, tamaño individual y tamaño total.
  • Rechaza nombres duplicados y extensiones no permitidas.
  • Comprueba la integridad cuando sea importante.
  • Extrae en un directorio temporal aislado.
  • No ejecutes automáticamente archivos extraídos.
  • Registra errores y elimina resultados incompletos.
  • Prueba paquetes normales y problemáticos.

Conclusión

zipfile en Python cubre los casos más habituales para crear y consumir archivos ZIP. Una implementación de producción debe combinar la API básica con inspección de metadatos, límites de recursos, validación de rutas y extracción controlada.

Al tratar cada miembro como entrada externa y verificar el destino antes de escribir, la aplicación se vuelve más predecible y resistente. Consulta la documentación oficial de zipfile y la guía de OWASP sobre extracción segura.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Carpetas y directorios para contextlib.chdir en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    contextlib.chdir: restaura directorios automáticamente

    Aprende contextlib.chdir en Python para cambiar directorios temporalmente, restaurar rutas y crear pruebas confiables sin errores de estado global.

    Ler mais

    Tempo de leitura: 6 minutos
    03/09/2026
    Monitoreo de rendimiento y ejecución de código Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    sys.monitoring: instrumentación de bajo overhead

    Aprende sys.monitoring en Python para instrumentar ejecución con bajo overhead, eventos selectivos, callbacks y observabilidad segura.

    Ler mais

    Tempo de leitura: 6 minutos
    03/09/2026
    Desarrollador organizando datos con operator.attrgetter en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    operator.attrgetter: ordena objetos por atributos

    Aprende operator.attrgetter en Python para ordenar, agrupar y transformar objetos por atributos simples o anidados con código claro.

    Ler mais

    Tempo de leitura: 4 minutos
    02/09/2026
    Programación asíncrona con asyncio.Runner en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    asyncio.Runner: reutiliza el event loop con seguridad

    Aprende asyncio.Runner en Python para reutilizar el event loop, controlar contexto, señales, debug, cancelación y cierre asíncrono seguro.

    Ler mais

    Tempo de leitura: 7 minutos
    02/09/2026
    Compresión de datos binarios con Zstandard en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: Zstandard con streams y diccionarios

    Aprende compression.zstd en Python para comprimir datos con Zstandard, streaming, diccionarios y límites seguros.

    Ler mais

    Tempo de leitura: 7 minutos
    01/09/2026
    Aplicación Python empaquetada como archivo ejecutable con zipapp
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    zipapp en Python: crea apps ejecutables

    Aprende zipapp en Python para empaquetar aplicaciones como archivos pyz ejecutables, incluir dependencias y distribuirlas con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    01/09/2026