Path.copy: copia archivos y carpetas con seguridad

Publicado el: 12/10/2026
Tempo de leitura: 5 minutos
Computadora con código que representa copia de archivos con Path.copy en Python

Path.copy() amplía el flujo orientado a objetos de pathlib para copiar archivos y directorios. En lugar de convertir rutas en cadenas y alternar entre varias APIs, una aplicación puede mantener navegación, validación y copia alrededor de objetos Path. Esto resulta útil en backups, sistemas de build, instaladores, migraciones, pruebas y automatizaciones.

Esta guía se centra en problemas reales: conflictos de destino, enlaces simbólicos, metadatos, permisos, fallos parciales, compatibilidad, rendimiento y verificación. Una llamada breve no elimina los riesgos del sistema de archivos; simplemente expresa mejor la intención.

Qué hace Path.copy

La ruta de origen es el objeto actual y el destino se entrega al método. Si el origen es un archivo, se replica su contenido. Si es un directorio, la operación puede copiar el árbol completo según las opciones disponibles y la versión de Python. El camino devuelto puede emplearse para registros y validaciones posteriores.

Antes de copiar, define el contrato: si se puede reemplazar un destino existente, si se siguen enlaces, qué metadatos deben conservarse y cómo se recuperará el sistema ante un fallo intermedio.

Ejemplo básico

from pathlib import Path

origen = Path("datos/informe.csv")
destino = Path("backup/informe.csv")

destino.parent.mkdir(parents=True, exist_ok=True)
resultado = origen.copy(destino)
print(resultado)

Crea explícitamente el directorio padre. Así el comportamiento es fácil de revisar. Conserva la ruta devuelta cuando debas comprobar tamaño, permisos o checksum.

Copia de directorios

Una copia recursiva normalmente no es una transacción atómica. Si un elemento falla, parte del árbol de destino puede quedar creado. Para flujos sensibles, copia primero a un directorio temporal, verifica el contenido y renómbralo al final.

from pathlib import Path
import tempfile

origen = Path("sitio")
destino = Path("dist/sitio")

with tempfile.TemporaryDirectory(dir=destino.parent) as temp:
    preparado = Path(temp) / "sitio"
    origen.copy(preparado)
    if destino.exists():
        raise FileExistsError(destino)
    preparado.replace(destino)

Este patrón reduce la posibilidad de presentar como válido un directorio incompleto. Comprueba las reglas del sistema cuando el temporal y el destino están en volúmenes distintos.

Política de sobrescritura

No supongas que un destino existente será reemplazado. Lee la documentación de la versión desplegada y define una política explícita. Un backup debería generar nombres versionados; un build reproducible puede eliminar su propia salida anterior; los documentos del usuario no deben sobrescribirse silenciosamente.

def copiar_sin_reemplazar(origen: Path, destino: Path) -> Path:
    if destino.exists():
        raise FileExistsError(f"El destino existe: {destino}")
    destino.parent.mkdir(parents=True, exist_ok=True)
    return origen.copy(destino)

En entornos concurrentes existe una carrera entre comprobar y copiar. Usa directorios de preparación únicos, bloqueos o nombres aleatorios cuando una colisión sea importante.

Enlaces simbólicos

Los enlaces simbólicos exigen una decisión de seguridad. Seguir un enlace copia el objetivo; preservarlo copia la referencia. Con entradas no confiables, seguir enlaces puede salir del árbol esperado y exponer archivos sensibles. Resuelve rutas con cuidado y exige una raíz permitida.

raiz = Path("entrada").resolve()
origen = Path("entrada/item").resolve()
if origen != raiz and raiz not in origen.parents:
    raise ValueError("El origen sale de la raíz permitida")

La comprobación ayuda, pero no elimina todas las condiciones de carrera. Un servicio privilegiado no debería procesar árboles mutables controlados por atacantes sin protecciones del sistema operativo.

Metadatos y permisos

Contenido, timestamps, bits de modo, propietario, ACL y atributos extendidos son aspectos diferentes. Una copia puede preservar algunos y perder otros, especialmente entre sistemas de archivos. Si la fidelidad es importante, prueba en cada plataforma y valida los atributos exactos.

Aplica privilegios mínimos en el destino. Los archivos de configuración y credenciales no deben quedar legibles por todos debido a permisos heredados. Ajusta el modo después de copiar y evita registrar datos confidenciales.

Manejo de errores

Captura excepciones específicas como FileNotFoundError, PermissionError, FileExistsError y OSError. Registra origen, destino y etapa, ocultando rutas sensibles en mensajes para usuarios.

try:
    origen.copy(destino)
except FileNotFoundError:
    print("El origen no existe")
except PermissionError:
    print("Permiso denegado")
except OSError as error:
    print(f"Fallo del sistema de archivos: {error}")

En lotes, decide si un error detiene todo. Una herramienta robusta separa éxitos y fallos y conserva datos suficientes para reintentar con seguridad.

Rendimiento

La velocidad depende de latencia, tamaño, caché, red y soporte del sistema operativo. No leas todo el archivo en memoria solo para duplicarlo. Mide cargas reales, comprueba espacio libre y limita concurrencia para no saturar el almacenamiento.

Los destinos remotos requieren más cuidado. Reintenta solo fallos transitorios, aplica espera progresiva y detecta resultados parciales. Los reintentos ciegos pueden crear duplicados o inconsistencias.

Verificación

Para archivos comunes, existencia y tamaño pueden bastar. Para artefactos críticos, compara hashes criptográficos. El hash añade I/O, pero detecta corrupción o copias incompletas.

import hashlib

def sha256(ruta: Path) -> str:
    digest = hashlib.sha256()
    with ruta.open("rb") as archivo:
        for bloque in iter(lambda: archivo.read(1024 * 1024), b""):
            digest.update(bloque)
    return digest.hexdigest()

En árboles, compara rutas relativas esperadas y calcula hashes de todos o de los archivos críticos. Guarda los resultados en logs estructurados.

Compatibilidad de versiones

Confirma la versión mínima antes de depender de Path.copy. Una biblioteca compatible con versiones antiguas puede centralizar un fallback con shutil.

def copiar_ruta(origen: Path, destino: Path) -> Path:
    if hasattr(origen, "copy"):
        return origen.copy(destino)
    import shutil
    if origen.is_dir():
        return Path(shutil.copytree(origen, destino))
    return Path(shutil.copy2(origen, destino))

Centralizar la compatibilidad evita condicionales dispersos y concentra la política de enlaces, sobrescritura, metadatos y registros.

Estrategia de pruebas

Prueba un archivo pequeño, archivo vacío, directorio anidado, destino existente, falta de permisos, enlaces simbólicos, nombres Unicode, rutas largas, disco lleno e interrupción durante una copia recursiva. Usa tempfile.TemporaryDirectory para aislar pruebas y ejecuta integración en todos los sistemas compatibles.

Diseño práctico

Un servicio reutilizable debe validar el origen, exigir una raíz permitida, crear padres, definir sobrescritura, controlar enlaces, preparar árboles en temporal, comprobar capacidad, verificar salidas importantes y devolver un resultado estructurado. Nunca aceptes rutas arbitrarias de usuarios sin normalización y reglas.

Consulta también pathlib en Python, shutil en Python, archivos en Python y manejo de excepciones. Revisa la documentación oficial de pathlib y la documentación de shutil.

Conclusión

Path.copy integra la copia con el estilo moderno de pathlib. Su interfaz concisa debe acompañarse de reglas explícitas de sobrescritura, tratamiento de enlaces, expectativas de metadatos, preparación segura de directorios, verificación y pruebas de compatibilidad. Con esos controles, simplifica flujos sin ocultar riesgos operativos.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Código en un monitor que representa acceso a memoria nativa con ctypes.memoryview_at en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ctypes.memoryview_at: memoria nativa sin copias

    Aprende ctypes.memoryview_at en Python para acceder a memoria nativa sin copias, validar punteros y reducir riesgos.

    Ler mais

    Tempo de leitura: 7 minutos
    12/10/2026
    Código Python en pantalla representando EnumDict y enumeraciones avanzadas
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    EnumDict: personaliza Enums con validación

    Aprende EnumDict en Python para personalizar EnumType, validar miembros y crear enumeraciones avanzadas con seguridad.

    Ler mais

    Tempo de leitura: 4 minutos
    11/10/2026
    Rack de servidores que representa el balanceo de conexiones con SO_REUSEPORT_LB en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    SO_REUSEPORT_LB: reparte conexiones entre workers

    Aprende SO_REUSEPORT_LB en Python para distribuir conexiones entre workers con pruebas, portabilidad y cierre ordenado.

    Ler mais

    Tempo de leitura: 5 minutos
    11/10/2026
    Código Python asíncrono en un portátil para inspect.markcoroutinefunction
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    markcoroutinefunction: detecta wrappers async

    Aprende inspect.markcoroutinefunction en Python para identificar wrappers asíncronos, integrar frameworks y evitar detecciones incorrectas.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Código Python para recorrer carpetas y archivos con Path.walk
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Path.walk: recorre directorios con seguridad

    Aprende Path.walk en Python para recorrer directorios, filtrar archivos, tratar errores y controlar la travesía con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Depuración de un proceso Python en terminal con código
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pdb -p: depura procesos Python en ejecución

    Aprende a conectar pdb a un proceso Python en ejecución, inspeccionar la pila y diagnosticar bloqueos de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    09/10/2026