Ir al contenido principal

Gestión de rutas y directorios

Introducción

En la programación real, trabajar con archivos implica mucho más que simplemente leerlos o escribirlos. Necesitamos manejar rutas de archivos, navegar entre directorios, crear carpetas, listar contenidos y muchas otras operaciones relacionadas con el sistema de archivos. Python proporciona excelentes herramientas para estas tareas a través del módulo os y, más recientemente, mediante el módulo pathlib, que ofrece una interfaz orientada a objetos mucho más intuitiva. En este artículo aprenderemos cómo gestionar rutas y directorios eficientemente en Python, algo esencial para cualquier aplicación que interactúe con el sistema de archivos.

Módulo os: el enfoque tradicional

El módulo os ha sido históricamente la forma estándar de manejar operaciones del sistema de archivos en Python.

Rutas y directorios con os.path

import os

# Obtener la ruta absoluta del directorio actual
directorio_actual = os.getcwd()
print(f"Directorio de trabajo actual: {directorio_actual}")

# Unir componentes de ruta (independiente del sistema)
ruta_archivo = os.path.join(directorio_actual, "datos", "usuarios.txt")
print(f"Ruta completa: {ruta_archivo}")

# Separar el nombre de archivo y su directorio
directorio, archivo = os.path.split(ruta_archivo)
print(f"Directorio: {directorio}")
print(f"Archivo: {archivo}")

# Obtener solo el nombre del archivo sin extensión
nombre_archivo, extension = os.path.splitext(archivo)
print(f"Nombre: {nombre_archivo}")
print(f"Extensión: {extension}")

# Verificar si una ruta existe
existe = os.path.exists(ruta_archivo)
print(f"¿Existe el archivo? {existe}")

# Comprobar si es un archivo o un directorio
if os.path.exists(ruta_archivo):
    es_archivo = os.path.isfile(ruta_archivo)
    es_directorio = os.path.isdir(ruta_archivo)
    print(f"¿Es archivo? {es_archivo}")
    print(f"¿Es directorio? {es_directorio}")

Operaciones con directorios

import os

# Crear un nuevo directorio
try:
    os.mkdir("nuevo_directorio")
    print("Directorio creado con éxito")
except FileExistsError:
    print("El directorio ya existe")

# Crear una estructura de directorios (crea directorios intermedios)
os.makedirs("carpeta/subcarpeta/datos", exist_ok=True)
print("Estructura de directorios creada")

# Listar el contenido de un directorio
contenido = os.listdir(directorio_actual)
print("Contenido del directorio actual:")
for elemento in contenido[:5]:  # Mostramos solo 5 elementos para no saturar
    print(f"- {elemento}")

# Eliminar un directorio vacío
try:
    os.rmdir("carpeta_vacia")
    print("Directorio eliminado")
except FileNotFoundError:
    print("El directorio no existe")
except OSError:
    print("El directorio no está vacío")

# Cambiar el directorio de trabajo
os.chdir("nuevo_directorio")
print(f"Nuevo directorio de trabajo: {os.getcwd()}")

Módulo pathlib: el enfoque moderno

Desde Python 3.4, el módulo pathlib ofrece una forma más orientada a objetos y elegante de trabajar con rutas.

Ventajas de pathlib

  • Sintaxis más clara y concisa
  • Operaciones encadenables
  • Manejo coherente entre distintos sistemas operativos
  • Métodos intuitivos para operaciones comunes

Trabajando con Path

from pathlib import Path

# Obtener el directorio actual
directorio = Path.cwd()
print(f"Directorio actual: {directorio}")

# Crear rutas
ruta_archivo = directorio / "datos" / "usuarios.txt"
print(f"Ruta de archivo: {ruta_archivo}")

# Obtener partes de la ruta
print(f"Nombre del archivo: {ruta_archivo.name}")
print(f"Directorio padre: {ruta_archivo.parent}")
print(f"Sufijo (extensión): {ruta_archivo.suffix}")
print(f"Nombre sin sufijo: {ruta_archivo.stem}")

# Verificar si existe
existe = ruta_archivo.exists()
print(f"¿Existe el archivo? {existe}")

# Comprobar tipo
if ruta_archivo.exists():
    es_archivo = ruta_archivo.is_file()
    es_directorio = ruta_archivo.is_dir()
    print(f"¿Es archivo? {es_archivo}")
    print(f"¿Es directorio? {es_directorio}")

Operaciones con directorios usando pathlib

from pathlib import Path

# Crear un directorio
nueva_carpeta = Path("nueva_carpeta")
nueva_carpeta.mkdir(exist_ok=True)
print(f"Directorio creado: {nueva_carpeta}")

# Crear estructura de directorios
estructura = Path("proyectos/python/tutorial")
estructura.mkdir(parents=True, exist_ok=True)
print(f"Estructura creada: {estructura}")

# Listar contenidos
directorio = Path.cwd()
print("Contenido del directorio:")
for elemento in list(directorio.iterdir())[:5]:  # Mostramos solo 5 elementos
    print(f"- {elemento.name}")

# Encontrar archivos por patrón
print("Archivos Python en el directorio:")
for archivo_py in directorio.glob("*.py"):
    print(f"- {archivo_py.name}")

# Buscar en todos los subdirectorios
print("Archivos Python en todos los subdirectorios:")
for archivo_py in directorio.glob("**/*.py"):
    print(f"- {archivo_py}")

Rutas absolutas vs relativas

Es importante entender la diferencia entre rutas absolutas y relativas:

  • Rutas absolutas: Comienzan desde la raíz del sistema de archivos y especifican la ubicación completa.
  • Rutas relativas: Se basan en el directorio de trabajo actual.
from pathlib import Path

# Ruta absoluta
ruta_absoluta = Path("/home/usuario/documentos/archivo.txt")
print(f"Ruta absoluta: {ruta_absoluta}")

# Ruta relativa
ruta_relativa = Path("documentos/archivo.txt")
print(f"Ruta relativa: {ruta_relativa}")

# Convertir relativa a absoluta
ruta_absoluta_desde_relativa = ruta_relativa.absolute()
print(f"Relativa convertida a absoluta: {ruta_absoluta_desde_relativa}")

Ejemplos prácticos

Organizador de archivos por tipo

from pathlib import Path
import shutil

def organizar_por_tipo(directorio):
    """Organiza los archivos de un directorio según su extensión."""
    directorio = Path(directorio)
    
    # Categorías comunes
    categorias = {
        ".txt": "Textos",
        ".pdf": "Documentos",
        ".jpg": "Imágenes",
        ".png": "Imágenes",
        ".py": "Python",
        ".mp3": "Audio",
        ".mp4": "Video"
    }
    
    # Crear carpetas para cada categoría
    for categoria in set(categorias.values()):
        carpeta = directorio / categoria
        carpeta.mkdir(exist_ok=True)
        
    # Mover archivos
    for archivo in directorio.iterdir():
        if archivo.is_file():
            extension = archivo.suffix.lower()
            categoria = categorias.get(extension, "Otros")
            carpeta_destino = directorio / categoria
            
            # Crear carpeta "Otros" si no existe
            if categoria == "Otros":
                carpeta_destino.mkdir(exist_ok=True)
                
            # Mover el archivo
            shutil.move(str(archivo), str(carpeta_destino / archivo.name))
            print(f"Movido {archivo.name} a {categoria}")

# Uso
# organizar_por_tipo("Descargas")

Buscador de archivos

from pathlib import Path
import time

def buscar_archivos(directorio, nombre=None, extension=None, modificado_dias=None):
    """
    Busca archivos en un directorio según varios criterios.
    
    Args:
        directorio: Directorio donde buscar
        nombre: Parte del nombre a buscar
        extension: Extensión de archivo (sin punto)
        modificado_dias: Archivos modificados en los últimos X días
    """
    directorio = Path(directorio)
    resultados = []
    
    # Configurar filtro de tiempo si se especifica
    tiempo_limite = None
    if modificado_dias is not None:
        tiempo_limite = time.time() - (modificado_dias * 24 * 60 * 60)
    
    # Iterar por todos los archivos
    for archivo in directorio.rglob("*"):
        if not archivo.is_file():
            continue
            
        # Filtrar por nombre
        if nombre and nombre.lower() not in archivo.name.lower():
            continue
            
        # Filtrar por extensión
        if extension and archivo.suffix.lower() != f".{extension.lower()}":
            continue
            
        # Filtrar por tiempo de modificación
        if tiempo_limite and archivo.stat().st_mtime < tiempo_limite:
            continue
            
        resultados.append(archivo)
    
    return resultados

# Uso
# archivos = buscar_archivos("Documentos", extension="pdf", modificado_dias=30)
# for archivo in archivos:
#     print(f"{archivo.name} - {archivo.stat().st_size} bytes")

Consideraciones importantes

Diferencias entre sistemas operativos

Aunque Python intenta abstraer las diferencias entre sistemas operativos, hay algunas consideraciones importantes:

  • Separadores de rutas: Windows usa \ mientras que Unix/Linux/macOS usan /.
  • Rutas raíz: Windows usa letras de unidad (como C:\), mientras que Unix usa una única raíz (/).
  • Nombres de archivo: Windows no distingue entre mayúsculas y minúsculas, pero Unix sí.

Utilizando os.path.join() o el operador / de pathlib, Python se encarga automáticamente de estas diferencias.

Permisos de acceso

Es importante considerar los permisos de acceso a archivos y directorios:

from pathlib import Path

archivo = Path("documento.txt")
if archivo.exists():
    # Verificar permisos
    permisos = {
        "lectura": os.access(archivo, os.R_OK),
        "escritura": os.access(archivo, os.W_OK),
        "ejecución": os.access(archivo, os.X_OK)
    }
    
    print(f"Permisos de {archivo.name}:")
    for permiso, tiene_permiso in permisos.items():
        print(f"- {permiso}: {'Sí' if tiene_permiso else 'No'}")

Resumen

En este artículo hemos explorado las diferentes formas de gestionar rutas y directorios en Python. Hemos visto el enfoque tradicional con el módulo os y el enfoque moderno con pathlib, que ofrece una sintaxis más clara y orientada a objetos. Aprendimos a crear rutas, manipular directorios, comprobar existencia de archivos y realizar operaciones comunes del sistema de archivos. Estas habilidades son fundamentales para cualquier programa que necesite trabajar con archivos, desde simples scripts hasta aplicaciones complejas que manejan grandes cantidades de datos.

En el próximo artículo, veremos cómo manejar errores específicos cuando trabajamos con archivos, lo que nos permitirá crear programas más robustos y resistentes a fallos.