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

    Grafo de dependencias y flujo de tareas en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    graphlib en Python: ordenación topológica

    Aprende graphlib en Python para ordenar dependencias, detectar ciclos y coordinar tareas independientes en paralelo.

    Ler mais

    Tempo de leitura: 6 minutos
    27/07/2026
    Código Python para contexto seguro en aplicaciones asíncronas
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    contextvars en Python: contexto seguro

    Aprende a usar contextvars en Python para aislar solicitudes, registros, hilos y tareas asyncio sin variables globales inseguras.

    Ler mais

    Tempo de leitura: 6 minutos
    26/07/2026
    Código Python con cached_property para guardar cálculos costosos
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    cached_property en Python: caché en objetos

    Aprende cached_property en Python para guardar cálculos costosos, invalidar valores y evitar cachés desactualizadas.

    Ler mais

    Tempo de leitura: 7 minutos
    25/07/2026
    Código Python con funciones especializadas por tipo
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    singledispatch en Python: funciones por tipo

    Aprende singledispatch en Python para crear funciones por tipo, reducir cadenas isinstance y organizar polimorfismo extensible con ejemplos.

    Ler mais

    Tempo de leitura: 7 minutos
    25/07/2026
    Código Python y atributos
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Descriptors en Python: guía práctica

    Aprende descriptors en Python con __get__, __set__, validación, property, almacenamiento por instancia, pruebas, herencia y buenas prácticas.

    Ler mais

    Tempo de leitura: 7 minutos
    22/07/2026
    Leitura de arquivos grandes em Python sem travar o sistema
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Cómo leer archivos gigantes con Python sin bloquear el sistema

    Aprende a leer archivos gigantes con Python usando iteración, bloques, generadores, chunks de Pandas, compresión y puntos de control.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026