Objetivo de Aprendizaje

Consolidar los conocimientos adquiridos en el manejo de archivos diseñando, implementando y depurando un sistema completo de préstamos para una biblioteca barrial, integrando el uso de JSON para datos complejos, CSV para registros tabulares y pathlib para la organización de directorios, todo respaldado por un manejo robusto de errores; para resolver un problema real de tu comunidad, desarrollando así un pensamiento computacional estructurado, autónomo y orientado al bienestar colectivo, comprendiendo cómo esta lógica fundamenta el funcionamiento de las bases de datos modernas.

Activación: De Estudiante a Constructor

Imagina que has pasado las últimas semanas aprendiendo a usar un martillo, una sierra, un nivel y una plomada por separado. Sabes cómo clavar un clavo y cómo cortar madera. Pero hoy, alguien te entrega los planos y te dice: "Ahora, construye una casa completa".

No se trata solo de usar las herramientas, sino de saber cuándo y cómo combinarlas para crear algo que funcione, sea útil y dure en el tiempo. Eso es exactamente lo que harás hoy.

La "Biblioteca Barrial San José" de tu comunidad tiene un problema: los libros se pierden, no saben quién tiene qué préstamo, y las multas se calculan a mano en cuadernos desgastados. Tú tienes el poder de cambiar eso. No es un ejercicio más de código; es tu obra maestra. Es el momento de demostrar que puedes transformar líneas de texto en un sistema que resuelve problemas reales.

💡 Reflexión inicial: ¿Alguna vez has visto un pequeño negocio o organización en tu barrio luchar con cuadernos y papeles? ¿Cómo crees que un sistema digital simple podría cambiar su día a día?

Desarrollo: Construyendo el Sistema

1. La Estructura del Proyecto

Antes de escribir código, un buen arquitecto organiza su terreno. Nuestro proyecto biblioteca_barrial necesita una estructura clara para separar responsabilidades:

biblioteca_barrial/
├── biblioteca.py              # Programa principal
├── config.json                # Configuración del sistema (parámetros externos)
├── datos/
│   ├── libros.json            # Catálogo de libros (datos complejos y anidados)
│   ├── prestamos.csv          # Historial de préstamos (datos tabulares)
│   └── vecinos.json           # Registro de vecinos
├── respaldos/                 # Respaldos automáticos organizados por fecha
│   └── 2026-07-16/
│       ├── libros_backup.json
│       └── prestamos_backup.csv
└── reportes/                  # Reportes generados (ej. vencidos)
    └── vencidos_2026-07-16.txt

2. El Código: Tu Obra Maestra

Para facilitar el aprendizaje y la revisión (principio DUA de representación múltiple), el código está organizado en secciones desplegables. Observa cómo cada parte tiene una única responsabilidad.

📦 Importaciones y Configuración
# biblioteca.py - Sistema de Préstamos de Biblioteca Barrial
# Proyecto integrador - Curso de Manejo de Archivos en Python

import json
import csv
from pathlib import Path
from datetime import datetime, timedelta
import shutil

# ============================================================
# CONFIGURACIÓN Y CONSTANTES
# ============================================================
CARPETA_DATOS = Path("datos")
CARPETA_RESPALDOS = Path("respaldos")
CARPETA_REPORTES = Path("reportes")
ARCHIVO_LIBROS = CARPETA_DATOS / "libros.json"
ARCHIVO_PRESTAMOS = CARPETA_DATOS / "prestamos.csv"
ARCHIVO_VECINOS = CARPETA_DATOS / "vecinos.json"
ARCHIVO_CONFIG = Path("config.json")

CONFIG_DEFAULT = {
    "biblioteca": {
        "nombre": "Biblioteca Barrial San José",
        "direccion": "Calle Principal s/n, Barrio San José",
        "telefono": "02-234-5678",
        "horario": "Lunes a Sábado, 9:00 - 18:00"
    },
    "prestamos": {
        "dias_prestamo": 14,
        "max_libros_por_vecino": 3,
        "multa_por_dia_vencido": 0.50
    },
    "sistema": {
        "version": "1.0.0",
        "ultimo_respaldo": None
    }
}
⚙️ Funciones de Inicialización y Carga
# ============================================================
# FUNCIONES DE INICIALIZACIÓN
# ============================================================
def inicializar_sistema():
    """Crea la estructura de carpetas y archivos necesarios"""
    print(" 🏛️ Inicializando Sistema de Biblioteca Barrial...")
    
    for carpeta in [CARPETA_DATOS, CARPETA_RESPALDOS, CARPETA_REPORTES]:
        carpeta.mkdir(exist_ok=True)
    
    config = cargar_configuracion()
    libros = cargar_libros()
    prestamos = cargar_prestamos()
    vecinos = cargar_vecinos()
    
    print(f" ✅ Sistema inicializado correctamente")
    return config, libros, prestamos, vecinos

def cargar_configuracion():
    if not ARCHIVO_CONFIG.exists():
        print(" ⚠️ Configuración no encontrada. Creando configuración inicial...")
        try:
            with open(ARCHIVO_CONFIG, "w", encoding="utf-8") as f:
                json.dump(CONFIG_DEFAULT, f, indent=4, ensure_ascii=False)
            return CONFIG_DEFAULT.copy()
        except Exception as e:
            print(f" ❌ Error al crear configuración: {e}")
            return CONFIG_DEFAULT.copy()
    
    try:
        with open(ARCHIVO_CONFIG, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception as e:
        print(f" ⚠️ Error al cargar configuración: {e}. Usando valores por defecto.")
        return CONFIG_DEFAULT.copy()

def cargar_prestamos():
    if not ARCHIVO_PRESTAMOS.exists():
        guardar_prestamos([])
        return []
    
    try:
        prestamos = []
        with open(ARCHIVO_PRESTAMOS, "r", encoding="utf-8", newline='') as f:
            lector = csv.DictReader(f)
            for fila in lector:
                fila['fecha_prestamo'] = datetime.strptime(fila['fecha_prestamo'], "%d/%m/%Y")
                fila['fecha_devolucion'] = datetime.strptime(fila['fecha_devolucion'], "%d/%m/%Y")
                prestamos.append(fila)
        return prestamos
    except Exception as e:
        print(f" ❌ Error al cargar préstamos: {e}")
        return []
📚 Funciones de Gestión (Libros, Vecinos, Préstamos)
# ============================================================
# FUNCIONES DE GESTIÓN DE LIBROS
# ============================================================
def registrar_libro(libros):
    print("\n 📚 Registrar nuevo libro")
    titulo = input("Título: ").strip()
    autor = input("Autor: ").strip()
    
    id_libro = len(libros) + 1
    libro = {
        "id": id_libro,
        "titulo": titulo,
        "autor": autor,
        "categoria": "General",
        "ubicacion": "Estante A",
        "estado": "disponible",
        "fecha_registro": datetime.now().strftime("%d/%m/%Y")
    }
    libros.append(libro)
    guardar_libros(libros)
    print(f" ✅ Libro registrado exitosamente (ID: {id_libro})")

# ============================================================
# FUNCIONES DE PRÉSTAMOS
# ============================================================
def registrar_prestamo(libros, prestamos, vecinos, config):
    print("\n 📖 Registrar préstamo")
    disponibles = [l for l in libros if l['estado'] == "disponible"]
    
    if not disponibles:
        print(" ❌ No hay libros disponibles para préstamo")
        return
    
    # (Lógica simplificada para el ejemplo: selección de libro y vecino)
    # Verificación de límite de préstamos:
    max_libros = config['prestamos']['max_libros_por_vecino']
    # ... lógica de validación y registro ...
    print(" ✅ Préstamo registrado exitosamente")
📊 Reportes, Respaldo y Programa Principal
# ============================================================
# FUNCIONES DE RESPALDO
# ============================================================
def crear_respaldo(config):
    print("\n 💾 Creando respaldo del sistema...")
    fecha_respaldo = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
    carpeta_respaldo = CARPETA_RESPALDOS / fecha_respaldo
    
    try:
        carpeta_respaldo.mkdir(parents=True, exist_ok=True)
        archivos_a_respaldar = [ARCHIVO_LIBROS, ARCHIVO_PRESTAMOS, ARCHIVO_VECINOS, ARCHIVO_CONFIG]
        
        for archivo_origen in archivos_a_respaldar:
            if archivo_origen.exists():
                archivo_destino = carpeta_respaldo / archivo_origen.name
                shutil.copy2(archivo_origen, archivo_destino)
        
        config['sistema']['ultimo_respaldo'] = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
        print(f" ✅ Respaldo creado en: {carpeta_respaldo}")
    except Exception as e:
        print(f" ❌ Error al crear respaldo: {e}")

# ============================================================
# PROGRAMA PRINCIPAL
# ============================================================
if __name__ == "__main__":
    print(" 🏛️ SISTEMA DE PRÉSTAMOS - BIBLIOTECA BARRIAL 📚")
    config, libros, prestamos, vecinos = inicializar_sistema()
    
    # Aquí iría el bucle while True del menú principal
    print(" 👋 ¡Sistema listo para operar!")

3. Entendiendo la Arquitectura

  • Separación de responsabilidades: Cada función hace una sola cosa y la hace bien (ej. cargar_libros() solo carga, no registra).
  • Manejo de errores en cada nivel: Cada interacción con archivos tiene su propio try/except. Si algo falla, el sistema no colapsa, se recupera con elegancia.
  • Datos en el formato correcto: JSON para datos complejos y anidados (libros, vecinos), CSV para datos tabulares (historial de préstamos), pathlib para rutas.
  • Configuración externa: config.json permite cambiar días de préstamo o multas sin tocar el código fuente.
⚠️ Errores Frecuentes a Evitar:
  • Olvidar encoding="utf-8" al abrir archivos, lo que corrompe tildes y ñ.
  • No convertir las fechas de string a objetos datetime al leer CSV, impidiendo calcular días de retraso.
  • Modificar una lista mientras se itera sobre ella (usa copias o comprensiones de lista).
🧠 Pregunta de reflexión: Si tuvieras que agregar un nuevo campo "calificación del libro (1-5 estrellas)" al sistema, ¿en qué archivo lo guardarías y por qué? (Pista: piensa en la naturaleza de los datos).

4. Más Allá del Curso: De Archivos a Bases de Datos

Lo que acabas de construir no es magia; es la base de todo sistema de datos. Cuando aprendas SQL, verás que:

  • SELECT * FROM libros WHERE autor = 'Juan León Mera' es lo mismo que tu función buscar_libros().
  • INSERT INTO vecinos... es lo mismo que vecinos.append() y guardar en JSON.
  • Las bases de datos son simplemente archivos muy bien organizados con índices, transacciones y optimizaciones. Ya tienes la mentalidad correcta.

El Reto: Expansión Comunitaria

Ahora que tienes el sistema base, es momento de personalizarlo y demostrar tu autonomía. Elige uno de los siguientes caminos y propón una solución (puede ser código modificado, un diagrama de flujo o un documento de diseño):

🛠️ Préstamo de Herramientas

Adapta el sistema para una ferretería comunitaria. Agrega campos como "estado de mantenimiento", "número de serie" y "multa por daño".

♿ Accesibilidad DUA

Diseña un "Modo Simple" en el menú: opciones de texto más grande, comandos de voz simulados o menús reducidos para adultos mayores.

📈 Análisis Predictivo

Agrega una función que lea el historial CSV y recomiende: "Los vecinos que pidieron este libro también pidieron...".

Criterios de éxito: Tu solución debe mantener el manejo robusto de errores, usar la estructura de carpetas adecuada y resolver una necesidad real de un usuario específico.

Evaluación Lúdica: Demuestra tu Maestría

Pregunta 1 de 5 Puntuación: 0

Cargando pregunta...