Objetivos de Aprendizaje
Al finalizar esta clase, serás capaz de:
- Leer y escribir archivos JSON (JavaScript Object Notation) con el módulo
json - Leer y escribir archivos CSV (Comma Separated Values) con el módulo
csv - Usar
pathlibpara manejo moderno de rutas - Implementar persistencia básica para el proyecto TaskFlow
- Manejar excepciones en operaciones de archivo
Archivos JSON (20 min)
JSON (JavaScript Object Notation) es un formato ligero para intercambio de datos. Python lo soporta nativamente.
Escribir JSON
import json
from pathlib import Path
# Datos a guardar
usuario = {
"id": 1,
"username": "juan123",
"email": "juan@example.com",
"activo": True
}
# Escribir archivo JSON
archivo = Path("data/usuario.json")
archivo.parent.mkdir(exist_ok=True) # Crear directorio si no existe
with open(archivo, "w", encoding="utf-8") as f:
json.dump(usuario, f, indent=4, ensure_ascii=False)
print(f"Archivo guardado en {archivo}")
Leer JSON
import json
from pathlib import Path
archivo = Path("data/usuario.json")
with open(archivo, "r", encoding="utf-8") as f:
datos = json.load(f)
print(datos["username"]) # "juan123"
print(datos["email"]) # "juan@example.com"
Lista de objetos JSON
usuarios = [
{"id": 1, "username": "juan", "email": "juan@test.com"},
{"id": 2, "username": "ana", "email": "ana@test.com"},
{"id": 3, "username": "pedro", "email": "pedro@test.com"}
]
# Guardar lista
with open("data/usuarios.json", "w", encoding="utf-8") as f:
json.dump(usuarios, f, indent=2, ensure_ascii=False)
# Leer lista
with open("data/usuarios.json", "r", encoding="utf-8") as f:
usuarios_cargados = json.load(f)
for u in usuarios_cargados:
print(f"@{u['username']} - {u['email']}")
Archivos CSV (20 min)
CSV (Comma Separated Values) es un formato tabular comun en hojas de calculo.
Escribir CSV
import csv
from pathlib import Path
tareas = [
{"id": 1, "titulo": "Aprender Python", "completada": False},
{"id": 2, "titulo": "Hacer proyecto", "completada": True},
{"id": 3, "titulo": "Estudiar FastAPI", "completada": False}
]
archivo = Path("data/tareas.csv")
with open(archivo, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["id", "titulo", "completada"])
writer.writeheader()
writer.writerows(tareas)
print(f"CSV guardado con {len(tareas)} tareas")
Leer CSV
import csv
from pathlib import Path
archivo = Path("data/tareas.csv")
with open(archivo, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
tareas = list(reader)
for tarea in tareas:
completada = "✅" if tarea["completada"] == "True" else "⬜"
print(f"{completada} {tarea['titulo']}")
Importante: CSV guarda todo como texto. Necesitas convertir tipos manualmente.
Modulo pathlib (10 min)
pathlib es la forma moderna de manejar rutas en Python.
from pathlib import Path
# Ruta actual
actual = Path.cwd()
print(f"Directorio actual: {actual}")
# Crear rutas
data_dir = Path("data")
archivo = data_dir / "usuarios.json"
# Verificar existencia
if not data_dir.exists():
data_dir.mkdir(parents=True, exist_ok=True)
# Informacion del archivo
if archivo.exists():
print(f"Nombre: {archivo.name}") # usuarios.json
print(f"Extension: {archivo.suffix}") # .json
print(f"Padre: {archivo.parent}") # data
print(f"Tamaño: {archivo.stat().st_size} bytes")
# Listar archivos
for f in data_dir.glob("*.json"):
print(f"Encontrado: {f}")
Ejercicio: Repositorio JSON (25 min)
Crear un repositorio que guarde usuarios en JSON:
# repositorio_usuario.py
import json
from pathlib import Path
from typing import Optional, List
class UsuarioRepositorioJSON:
"""Repositorio que persiste usuarios en archivo JSON."""
def __init__(self, archivo: str = "data/usuarios.json"):
self.archivo = Path(archivo)
self._asegurar_archivo()
def _asegurar_archivo(self):
"""Crea el archivo si no existe."""
self.archivo.parent.mkdir(parents=True, exist_ok=True)
if not self.archivo.exists():
self._guardar_todos([])
def _leer_todos(self) -> List[dict]:
"""Lee todos los usuarios del archivo."""
with open(self.archivo, "r", encoding="utf-8") as f:
return json.load(f)
def _guardar_todos(self, usuarios: List[dict]):
"""Guarda todos los usuarios en el archivo."""
with open(self.archivo, "w", encoding="utf-8") as f:
json.dump(usuarios, f, indent=2, ensure_ascii=False)
def crear(self, usuario: dict) -> dict:
"""Crea un nuevo usuario."""
usuarios = self._leer_todos()
nuevo_id = max([u["id"] for u in usuarios], default=0) + 1
usuario["id"] = nuevo_id
usuarios.append(usuario)
self._guardar_todos(usuarios)
return usuario
def obtener_por_id(self, id: int) -> Optional[dict]:
"""Obtiene un usuario por su ID."""
usuarios = self._leer_todos()
for u in usuarios:
if u["id"] == id:
return u
return None
def obtener_todos(self) -> List[dict]:
"""Obtiene todos los usuarios."""
return self._leer_todos()
def actualizar(self, id: int, datos: dict) -> Optional[dict]:
"""Actualiza un usuario existente."""
usuarios = self._leer_todos()
for i, u in enumerate(usuarios):
if u["id"] == id:
usuarios[i].update(datos)
usuarios[i]["id"] = id # No cambiar ID
self._guardar_todos(usuarios)
return usuarios[i]
return None
def eliminar(self, id: int) -> bool:
"""Elimina un usuario."""
usuarios = self._leer_todos()
for i, u in enumerate(usuarios):
if u["id"] == id:
usuarios.pop(i)
self._guardar_todos(usuarios)
return True
return False
# === PRUEBAS ===
if __name__ == "__main__":
repo = UsuarioRepositorioJSON()
# Crear usuarios
u1 = repo.crear({"username": "juan", "email": "juan@test.com"})
u2 = repo.crear({"username": "ana", "email": "ana@test.com"})
print(f"Creados: {u1['id']}, {u2['id']}")
# Listar
print(f"Total: {len(repo.obtener_todos())} usuarios")
# Actualizar
repo.actualizar(u1["id"], {"email": "nuevo@test.com"})
# Eliminar
repo.eliminar(u2["id"])
print(f"Despues de eliminar: {len(repo.obtener_todos())}")
E4 Laboratorio: Implementa un repositorio CSV para tareas con las mismas operaciones CRUD.
Resumen
- json.dump()/json.load(): Escribir/leer JSON
- csv.DictWriter/DictReader: Escribir/leer CSV
- pathlib.Path: Manejo moderno de rutas
- with open(): Context manager para archivos
- encoding="utf-8": Siempre especificar encoding