Crear una copia de seguridad ZIP con fecha y verificar lo archivado
Crea un archivo ZIP con fecha a partir de una carpeta sin modificar los originales y verifica después que todos los archivos de origen aparezcan en el archivo con el mismo contenido. Una pequeña carpeta sintética permite comprobar manualmente las rutas, tamaños y totales esperados.
Contenido revisado 2026.09.20Incluye archivos de ejemplo
Ver el índice
La traducción se ha realizado con IA. Comprueba el código, las unidades y los valores junto con el original. La revisión por hablantes nativos de cada idioma aún no se ha completado. English
Para quién esEsta guía está dirigida a personas que quieren una copia de seguridad sencilla de una carpeta con fecha y un paso explícito de verificación, en lugar de asumir que la creación del archivo se realizó correctamente.
Preparación
Python 3.12 y un comando de terminal que inicie esa versión.
Una carpeta de trabajo donde los scripts puedan crear carpetas dentro de outputs.
Permiso de lectura para los archivos de origen y suficiente espacio en disco para el archivo ZIP.
Solo se requiere la biblioteca estándar de Python: datetime, hashlib, pathlib y zipfile.
01Definir qué debe contener la copia de seguridad
El script archivará los archivos normales de una carpeta de origen, incluidos los archivos de subcarpetas anidadas. Las rutas dentro del ZIP se guardan relativas a la carpeta de origen, de modo que un archivo como reports/week1.txt permanece como reports/week1.txt en lugar de convertirse en una ruta absoluta del sistema de archivos.
El nombre del archivo contiene la fecha local actual en formato YYYY-MM-DD. Si el ejemplo se ejecuta el 2026-09-20, el nombre esperado es backup_demo_2026-09-20.zip. Si se vuelve a ejecutar el mismo día con el mismo destino, el script se detiene en lugar de sustituir la copia de seguridad anterior.
02Crear una carpeta de origen sintética
El siguiente conjunto de datos es sintético y fue creado específicamente para este artículo. Guarda el script de preparación como create_backup_demo.py. Crea cuatro archivos con contenidos de bytes exactos, incluido un archivo dentro de una carpeta reports anidada.
python
from pathlib import Path
SOURCE = Path("outputs") / "backup_demo"
FILES = {
"notes.txt": b"alpha\n",
"reports/week1.txt": b"beta\n",
"reports/week2.txt": b"gamma\n",
"settings.ini": b"mode=test\n",
}
SOURCE.parent.mkdir(parents=True, exist_ok=True)
SOURCE.mkdir() # Stop if the synthetic source already exists.
for relative_name, content in FILES.items():
target = SOURCE / relative_name
target.parent.mkdir(parents=True, exist_ok=True)
with target.open("xb") as stream:
stream.write(content)
text
python create_backup_demo.py
Ruta relativa
Contenido exacto
Bytes
notes.txt
alpha más salto de línea
6
reports/week1.txt
beta más salto de línea
5
reports/week2.txt
gamma más salto de línea
6
settings.ini
mode=test más salto de línea
10
El origen contiene 4 archivos normales con un total de 27 bytes de contenido sin comprimir: 6 + 5 + 6 + 10. El tamaño final del propio archivo ZIP no puede predecirse a partir de ese total porque la compresión ZIP y los metadatos del archivo añaden su propia sobrecarga.
03Preparar la ejecución de la copia de seguridad con fecha
Guarda el script principal como dated_zip_backup.py junto al script de preparación.
Mantén SOURCE como outputs/backup_demo para este ejemplo.
Mantén BACKUP_DIR como outputs/backups para que el archivo quede fuera de la carpeta de origen.
Ejecuta el script desde el mismo directorio de trabajo.
text
python dated_zip_backup.py
El script comprueba que el origen exista y que el directorio de copia de seguridad no esté dentro del directorio de origen. La carpeta padre de la copia de seguridad puede existir previamente. El archivo ZIP con fecha no debe existir.
04Crear el ZIP y verificar cada miembro
El script crea primero una lista ordenada de archivos de origen. Crea el archivo mediante creación exclusiva, escribe cada archivo con compresión ZIP_DEFLATED y después vuelve a abrir el archivo para verificarlo. La verificación compara la lista de miembros prevista, comprueba la integridad CRC con testzip y compara los hashes SHA-256 de los archivos de origen y archivados.
python
from datetime import date
import hashlib
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile
SOURCE = Path("outputs") / "backup_demo"
BACKUP_DIR = Path("outputs") / "backups"
CHUNK_SIZE = 1024 * 1024
def hash_file(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
while chunk := stream.read(CHUNK_SIZE):
digest.update(chunk)
return digest.hexdigest()
def hash_member(archive: ZipFile, member_name: str) -> str:
digest = hashlib.sha256()
with archive.open(member_name, "r") as stream:
while chunk := stream.read(CHUNK_SIZE):
digest.update(chunk)
return digest.hexdigest()
def main() -> None:
source_root = SOURCE.resolve(strict=True)
if not source_root.is_dir():
raise ValueError("SOURCE must be a directory.")
backup_root = BACKUP_DIR.resolve()
if backup_root.is_relative_to(source_root):
raise ValueError("BACKUP_DIR must be outside SOURCE.")
files = sorted(
path for path in source_root.rglob("*")
if path.is_file() and not path.is_symlink()
)
if not files:
raise ValueError("SOURCE contains no regular files to back up.")
BACKUP_DIR.mkdir(parents=True, exist_ok=True)
archive_name = f"{source_root.name}_{date.today().isoformat()}.zip"
archive_path = BACKUP_DIR / archive_name
if archive_path.exists():
raise FileExistsError(f"Backup already exists: {archive_path}")
expected = {}
with archive_path.open("xb") as raw:
with ZipFile(raw, "w", compression=ZIP_DEFLATED) as archive:
for path in files:
relative = path.relative_to(source_root).as_posix()
expected[relative] = (path.stat().st_size, hash_file(path))
archive.write(path, arcname=relative)
with ZipFile(archive_path, "r") as archive:
bad_member = archive.testzip()
if bad_member is not None:
raise RuntimeError(f"CRC check failed: {bad_member}")
members = [info for info in archive.infolist() if not info.is_dir()]
actual_names = [info.filename for info in members]
expected_names = list(expected)
if actual_names != expected_names:
raise RuntimeError("Archive member list does not match the source list.")
for info in members:
expected_size, expected_hash = expected[info.filename]
if info.file_size != expected_size:
raise RuntimeError(f"Size mismatch: {info.filename}")
if hash_member(archive, info.filename) != expected_hash:
raise RuntimeError(f"Hash mismatch: {info.filename}")
total_bytes = sum(size for size, _ in expected.values())
print(f"Verified {len(expected)} files totaling {total_bytes} bytes.")
print(f"Archive: {archive_path.as_posix()}")
if __name__ == "__main__":
main()
El código omite los enlaces simbólicos y archiva únicamente archivos normales. Los hashes esperados se calculan a partir del origen inmediatamente antes de añadir cada archivo. En una carpeta local normal que permanezca sin cambios durante la ejecución, esto proporciona una comparación útil a nivel de contenido después de crear el archivo.
05Comprobar manualmente el archivo esperado
Si el script se ejecuta el 2026-09-20, la ruta esperada del archivo es outputs/backups/backup_demo_2026-09-20.zip. El ZIP debería contener exactamente las siguientes cuatro rutas de miembros.
Miembro del archivo
Bytes sin comprimir
notes.txt
6
reports/week1.txt
5
reports/week2.txt
6
settings.ini
10
La carpeta reports anidada está representada por las propias rutas de los miembros. El script no necesita una entrada de directorio independiente para reports porque los archivos ya incluyen esa ruta relativa.
La salida de consola esperada que aparece a continuación se obtuvo manualmente para una ejecución el 2026-09-20. No es un registro capturado de ejecución.
Abre el ZIP con un visor de archivos comprimidos y confirma que haya exactamente 4 archivos con las rutas relativas esperadas.
Extrae el archivo en una ubicación temporal independiente y compara el contenido de texto con los 4 archivos de origen.
Confirma que los archivos originales sigan existiendo en outputs/backup_demo después de completar la copia de seguridad.
Ejecuta de nuevo el script de copia de seguridad en la misma fecha sin cambiar el destino. Debería detenerse con FileExistsError en lugar de sustituir el archivo existente.
Si quieres confirmar que la verificación sigue el contenido nuevo, modifica una copia de un archivo de origen en una prueba separada y crea una nueva copia de seguridad con un nombre de archivo distinto.
No utilices el tamaño del archivo comprimido como comprobación principal. Debido a la compresión, un archivo válido puede ser menor o mayor que el total sin comprimir del origen, según los datos y los metadatos.
07Reconocer errores comunes
Síntoma
Qué comprobar
FileNotFoundError
Comprueba SOURCE y el directorio de trabajo del terminal. Para este ejemplo, ejecuta primero el script de preparación sintético.
FileExistsError
Ya existe una copia de seguridad con el mismo nombre fechado. Revísala y elige otro destino o espera a otra fecha de copia prevista en lugar de sobrescribirla.
PermissionError
Confirma que el script pueda leer todos los archivos de origen y crear archivos dentro de BACKUP_DIR.
CRC check failed
Considera el archivo como fallido. No dependas de él como copia de seguridad; investiga posibles errores de almacenamiento o escritura y crea un archivo nuevo.
Member list mismatch
Es posible que el origen haya cambiado durante la ejecución o que el contenido del archivo no coincida con la lista de archivos creada al principio.
Hash or size mismatch
Considera que la verificación ha fallado. Mantén el origen sin cambios e investiga la discrepancia antes de crear un nuevo archivo.
Si se produce una excepción después de crear el archivo ZIP, puede quedar en la carpeta de copias un archivo parcial o no verificado. El script no lo elimina automáticamente porque una limpieza automática puede ocultar información útil para diagnosticar el fallo.
08Comprender lo que esta copia de seguridad no garantiza
Este es un flujo de archivado mediante copia de archivos, no una instantánea transaccional del sistema de archivos. Si otra aplicación modifica un archivo mientras se calcula su hash o se archiva, el resultado puede quedar inconsistente. Para datos importantes, detén las escrituras en el origen o utiliza un sistema de copia de seguridad con capacidad de instantáneas.
El ejemplo no conserva todas las propiedades del sistema de archivos. Los permisos, la propiedad, las listas de control de acceso, los atributos extendidos, los flujos de datos alternativos, los enlaces simbólicos y los metadatos específicos de aplicaciones pueden requerir otra herramienta de copia de seguridad. ZIP es útil para colecciones de archivos portátiles, pero no es una imagen completa de un sistema de archivos.
Un archivo verificado sigue siendo una sola copia. Un plan de copia de seguridad real debería considerar múltiples copias, fallos de almacenamiento, eliminación accidental, ransomware, periodos de retención, cifrado y si la recuperación se ha probado realmente. La verificación aquí muestra que este archivo coincidía con el contenido del origen observado durante esta ejecución; no establece una estrategia completa de recuperación ante desastres.
Se comprobaron manualmente los tamaños de los cuatro archivos sintéticos como 6, 5, 6 y 10 bytes.
Se calculó manualmente el total sin comprimir del origen como 27 bytes.
Se enumeraron manualmente las rutas esperadas de los miembros del archivo, incluidas las dos rutas anidadas de reports.
Se revisó el código para confirmar que los archivos de origen se leen, el ZIP se escribe dentro de outputs y una copia con la misma fecha ya existente hace que la ejecución se detenga.
Se revisó la lógica de verificación para las pruebas CRC, la comparación de la lista de miembros, la comparación del tamaño sin comprimir y la comparación SHA-256.
Se obtuvieron manualmente el nombre esperado del archivo para 2026-09-20 y la salida de consola.
Límites de la verificación
El código no fue ejecutado por el autor de esta respuesta; no se creó ni se abrió ningún archivo ZIP.
Los valores SHA-256 y los resultados CRC no se calcularon manualmente porque la lógica de comparación es la comprobación relevante para este ejemplo.
No se probaron cambios simultáneos en el origen, errores de permisos, corrupción de almacenamiento, escrituras interrumpidas, enlaces simbólicos ni rendimiento con directorios grandes.
No se predijo el tamaño comprimido del archivo porque depende del resultado de la compresión y de los metadatos ZIP.
Las URL de la documentación oficial se proporcionaron a partir de ubicaciones de documentación conocidas, pero no se comprobaron en línea.
Las explicaciones y los ejemplos son de elaboración propia. Puedes consultar los comportamientos y conceptos relacionados en las siguientes fuentes oficiales.
Recorre las subcarpetas y registra en una tabla las rutas, extensiones, tamaños y fechas de modificación de los archivos. Empieza con 4 archivos de ejemplo pequeños, manteniendo intactos los originales y los resultados existentes.
Combina en orden archivos CSV con la misma estructura de columnas y añade una columna source_file. Usa conjuntos de datos pequeños para comprobar nombres de elementos con comas, columnas faltantes y salidas ya existentes.
Compara los nombres antiguos y nuevos en una tabla y comprueba conflictos. Solo un --apply explícito crea copias en una carpeta nueva, manteniendo los originales.