martes, 5 de mayo de 2026

DATOS. Directorios y archivos

Subdirectorios

En cuanto un directorio contiene un determinado número de archivos, y éstos se pueden diferenciar por algún criterio, es habitual que el directorio se divida, generándose una estructura de subdirectorios. Un caso concreto de esto son los expedientes SEO. Además de ser una tendencia lógica, que esto se produzca es una medida de la madurez del expediente y de la funcionalidad que éste tiene como recurso de intervención del SEO. Por ello el estudio de la estructura debe ser parte del análisis de los expedientes SEO. Este estudio se puede automatizar mediante script.

Voy a presentar en esta entrada algunos script dirigidos a facilitar la automatización en este nivel, empezando por la identificación del número de subdirectorios que contiene un listado de directorios.



from pathlib import Path
import csv
from collections import Counter

#Función secundaria. Guarda el listado detallado en un archivo CSV.

def crear_csv(datos, ruta_destino):
    nombre_archivo = Path(ruta_destino) / "listado_directorios.csv"
    try:
        with open(nombre_archivo, mode='w', newline='', encoding='utf-8') as f:
            escritor = csv.writer(f)
            escritor.writerow(["Directorio", "Num_Subcarpetas"])
            for fila in datos:
                escritor.writerow([fila['nombre'], fila['subs']])
        print(f"\n[SISTEMA] Archivo guardado en: {nombre_archivo}")
    except Exception as e:
        print(f"\n[ERROR] No se pudo crear el CSV: {e}")

# Función secundaria. Calcula y muestra la frecuencia de subdirectorios.

def generar_sintesis(datos):
    total_directorios = len(datos)
    if total_directorios == 0:
        return
    frecuencias = Counter(d['subs'] for d in datos)
    
    print("\n--- RESUMEN ESTADÍSTICO DE FRECUENCIAS ---")
    for num_subs, cantidad in sorted(frecuencias.items()):
        porcentaje = (cantidad / total_directorios) * 100
        print(f"CARPETAS con {num_subs} subdirectorios : {cantidad} carpetas -- {porcentaje:.2f}% sobre total")

# Función principal: Coordina el listado, el CSV y la estadística.

def procesar_ruta(ruta_analizar, ruta_guardado):
    path_base = Path(ruta_analizar)
    
    if not path_base.exists() or not path_base.is_dir():
        print("La ruta proporcionada no es válida.")
        return

    resultados = []

    print(f"\nListado de directorios en: {path_base.resolve()}\n")
    
    for item in path_base.iterdir():
        if item.is_dir():
            try:
                conteo = sum(1 for sub in item.iterdir() if sub.is_dir())   # Contamos subdirectorios inmediatos
                resultados.append({'nombre': item.name, 'subs': conteo})
                print(f"[DIRECTORIO] {item.name}: {conteo} subcarpetas")	# Visualización solicitada
            except PermissionError:
                continue 
    crear_csv(resultados, ruta_guardado)	 								# Llamada a funciones secundarias
    generar_sintesis(resultados)

# --- LLAMADA A LA FUNCIÓN ---

if __name__ == "__main__":
    # Define aquí tus rutas
    ruta_objetivo = r""      		# Ruta a explorar
    ruta_donde_archivar = r""       # Ruta para guardar el CSV
    
    procesar_ruta(ruta_objetivo, ruta_donde_archivar)


Este script lee un conjunto de directorios y genera un listado CSV en el que se recoge el número de subdirectorios que contiene cada uno. Para ello utiliza dos funciones secundarias y una principal. La funcionalidad de cada una de ellas queda explicada en los comentarios del script.

Este otro script añade al anterior el conteo de todos los archivos que contie el directorio.


  
from pathlib import Path
import csv
from collections import Counter

#Función secundaria. Guarda el listado detallado en un archivo CSV.

def crear_csv(datos, ruta_destino):
    nombre_archivo = Path(ruta_destino) / "listado_completo_directorios.csv"
    try:
        with open(nombre_archivo, mode='w', newline='', encoding='utf-8') as f:
            escritor = csv.writer(f)
            # Añadimos la nueva columna de archivos totales
            escritor.writerow(["Directorio", "Num_Subcarpetas_Directas", "Num_Archivos_Totales"])
            for fila in datos:
                escritor.writerow([fila['nombre'], fila['subs'], fila['archivos']])
        print(f"\n[SISTEMA] Archivo guardado en: {nombre_archivo}")
    except Exception as e:
        print(f"\n[ERROR] No se pudo crear el CSV: {e}")

#Función secundaria. Calcula y muestra la frecuencia de subdirectorios.

def generar_sintesis(datos):
    total_directorios = len(datos)
    if total_directorios == 0:
        return
    frecuencias = Counter(d['subs'] for d in datos)
    print("\n" + "="*50)
    print("--- RESUMEN ESTADÍSTICO DE FRECUENCIAS ---")
    for num_subs, cantidad in sorted(frecuencias.items()):
        porcentaje = (cantidad / total_directorios) * 100
        print(f"CARPETAS con {num_subs} subdirectorios : {cantidad} carpetas -- {porcentaje:.2f}% sobre total")
    print("="*50)

#Función principal. oordina el análisis profundo de la ruta.

def procesar_ruta(ruta_analizar, ruta_guardado):
    path_base = Path(ruta_analizar)
    if not path_base.exists() or not path_base.is_dir():
        print(f"Error: '{ruta_analizar}' no es una ruta válida.")
        return
    resultados = []
    print(f"\nAnalizando contenido en: {path_base.resolve()}\n")
    print(f"{'DIRECTORIO':<25} | {'SUBS':<6} | {'ARCHIVOS (TOTAL)'}")
    print("-" * 60)
    
    for item in path_base.iterdir():
        if item.is_dir():
            try:
                conteo_subs = sum(1 for sub in item.iterdir() if sub.is_dir())	 # 1. Contar subdirectorios directos (primer nivel)
                conteo_archivos = sum(1 for f in item.rglob('*') if f.is_file()) # 2. Contar TODOS los archivos rglob('*')
                resultados.append({
                    'nombre': item.name, 
                    'subs': conteo_subs, 
                    'archivos': conteo_archivos
                })
                print(f"[DIRECTORIO] {item.name:<12}: {conteo_subs:>3} subs | {conteo_archivos:>5} archivos")	# Visualización por CMD 
            except PermissionError:
                print(f"[!] Sin permiso para acceder a: {item.name}")
                continue
    crear_csv(resultados, ruta_guardado)	    								# Ejecución de reportes
    generar_sintesis(resultados)

# --- SECCIÓN DE LLAMADA A LA FUNCIÓN ---

if __name__ == "__main__":
    # Ajusta estas rutas según tu necesidad
    ruta_objetivo = r""      					# Ruta a explorar
    ruta_donde_archivar = r""                   # Ruta para guardar el CSV
    
    procesar_ruta(ruta_objetivo, ruta_donde_archivar)


Finalmente, en este script cambiamos el enfoque y en vez de trabajar con colecciones de directorios lo vamos a hacer con un directorio en concreto, pero incrementando el detalle del estudio de su estructura (subdirectorios) y de su contenido (archivos), generando un informe útil para el estudio estructural del expediente.



from pathlib import Path
import csv
from collections import Counter

#Función secundaria. Guarda el desglose detallado en un archivo CSV.

def crear_csv(datos, ruta_destino):
    nombre_archivo = Path(ruta_destino) / "estructura_analizada.csv"
    try:
        with open(nombre_archivo, mode='w', newline='', encoding='utf-8') as f:
            escritor = csv.writer(f)
            escritor.writerow([
                "Entrada", 
                "Subcarpetas_Directas", 
                "Archivos_Raiz", 
                "Archivos_en_Subdirs", 
                "Total_Archivos"
            ])
            for fila in datos:
                escritor.writerow([
                    fila['nombre'], 
                    fila['subs'], 
                    fila['archivos_raiz'], 
                    fila['archivos_sub'], 
                    fila['total_archivos']
                ])
        print(f"\n[SISTEMA] Reporte CSV generado en: {nombre_archivo}")
    except Exception as e:
        print(f"\n[ERROR] No se pudo crear el CSV: {e}")

# Función secundaria. Muestra la estadística de frecuencias por consola.

def generar_sintesis(datos):
    total_entradas = len(datos)
    if total_entradas == 0:
        return
    frecuencias = Counter(d['subs'] for d in datos
    print("\n" + "="*85)
    print("--- RESUMEN ESTADÍSTICO DE FRECUENCIAS (Basado en Subdirectorios Directos) ---")
    for num_subs, cantidad in sorted(frecuencias.items()):
        porcentaje = (cantidad / total_entradas) * 100
        print(f"ENTRADAS con {num_subs} subdirectorios directos: {cantidad} unidades -- {porcentaje:.2f}%")
    print("="*85)

# Función principal. Analiza la ruta e incluye el conteo del directorio raíz

def procesar_estructura_principal(ruta_objetivo):
    path_base = Path(ruta_objetivo)
    if not path_base.exists() or not path_base.is_dir():
        print(f"\n[ERROR] La ruta '{ruta_objetivo}' no es válida.")
        return
    resultados = []
    print(f"\nExplorando: {path_base.resolve()}")
    header = f"{'ENTRADA/CARPETA':<25} | {'SUBS':<5} | {'RAIZ':<7} | {'EN SUBS':<8} | {'TOTAL'}"
    print(header)
    print("-" * len(header))
    
    # --- PARTE 1: Analizar la propia carpeta raíz introducida ---
    try:
        subs_raiz = sum(1 for x in path_base.iterdir() if x.is_dir())
        archivos_totales_raiz = sum(1 for x in path_base.rglob('*') if x.is_file())
        archivos_directos_raiz = sum(1 for x in path_base.iterdir() if x.is_file())
        resultados.append({						 # Añadimos la entrada de la carpeta principal
            'nombre': f"RAIZ ({path_base.name})",
            'subs': subs_raiz,
            'archivos_raiz': archivos_directos_raiz,
            'archivos_sub': archivos_totales_raiz - archivos_directos_raiz,
            'total_archivos': archivos_totales_raiz
        })
        print(f"{'-- DIRECTORIO RAIZ --':<25} | {subs_raiz:>5} | {archivos_directos_raiz:>7} | {archivos_totales_raiz - archivos_directos_raiz:>8} | {archivos_totales_raiz:>5}")
    except PermissionError:
        print(f"{'RAIZ':<25} | [!] Acceso denegado")

    # --- PARTE 2: Analizar los subdirectorios internos (si los hay) ---
    for item in path_base.iterdir():
        if item.is_dir():
            try:
                conteo_subs = sum(1 for x in item.iterdir() if x.is_dir())
                total_archivos = sum(1 for x in item.rglob('*') if x.is_file())
                if conteo_subs == 0:
                    archivos_raiz = total_archivos
                    archivos_en_subdirs = 0
                else:
                    archivos_raiz = sum(1 for x in item.iterdir() if x.is_file())
                    archivos_en_subdirs = total_archivos - archivos_raiz
                resultados.append({
                    'nombre': item.name, 
                    'subs': conteo_subs, 
                    'archivos_raiz': archivos_raiz,
                    'archivos_sub': archivos_en_subdirs,
                    'total_archivos': total_archivos
                })  
                print(f"{item.name[:25]:<25} | {conteo_subs:>5} | {archivos_raiz:>7} | {archivos_en_subdirs:>8} | {total_archivos:>5}")
            except PermissionError:
                continue
    if resultados:
        crear_csv(resultados, path_base)
        generar_sintesis(resultados)

# --- SEGMENTO DE LLAMADA A LA FUNCIÓN ---

if __name__ == "__main__":
    ruta_input = input("Introduce la ruta del directorio a analizar: ").strip().replace('"', '')
    procesar_estructura_principal(ruta_input)


No hay comentarios:

Publicar un comentario

Comenta esta entrada