lección 4

Leyendo y escribiendo archivos

Tu programa toca el mundo exterior: leer CSVs, escribir resultados, trabajar con JSON. El I/O básico que todo ingeniero de datos necesita.

55 min

Hasta ahora, tus datos vivían dentro del script — hardcoded en variables. Pero en el mundo real, los datos viven en ARCHIVOS: CSVs que exporta el equipo de finanzas, JSONs que devuelve una API, logs de texto que genera un servidor. Tu trabajo como ingeniero de datos es LEER esos archivos, transformarlos y ESCRIBIR los resultados. Hoy aprendes el I/O (Input/Output) fundamental.

Piensa en esto: un pipeline de datos típico empieza leyendo un archivo de un directorio, lo procesa y escribe el resultado en otro directorio. Es como una fábrica — materia prima entra, producto terminado sale. Python tiene herramientas integradas para hacer exactamente eso, sin instalar nada extra.

### open() y with: la puerta al sistema de archivos

La función open() es tu punto de entrada al sistema de archivos. Abre un archivo y te devuelve un "manejador" que puedes leer o escribir. La forma correcta de usar open() es SIEMPRE con la sentencia "with" — que garantiza que el archivo se cierra automáticamente, incluso si hay un error.

1# Escribir un archivo de texto
2with open("datos_ejemplo.txt", "w", encoding="utf-8") as f:
3 f.write("producto,cantidad,precio\n")
4 f.write("Laptop,5,1299.99\n")
5 f.write("Monitor,12,349.50\n")
6 f.write("Teclado,30,79.99\n")
7
8print("Archivo creado.")
9
10# Leer el archivo completo
11with open("datos_ejemplo.txt", "r", encoding="utf-8") as f:
12 contenido = f.read()
13print(contenido)
14
15# Leer línea por línea (mejor para archivos grandes)
16with open("datos_ejemplo.txt", "r", encoding="utf-8") as f:
17 for linea in f:
18 print(linea.strip()) # strip() quita el \n del final

with open() es el patrón estándar. "w" escribe, "r" lee, "a" añade al final.

SIEMPRE especifica encoding="utf-8" al abrir archivos. Sin esto, en Windows Python usa una codificación diferente (cp1252) y los caracteres especiales (acentos, ñ, €) se corrompen. Este bug es invisible hasta que explota en producción con datos reales.

### Leer CSVs con el módulo csv

CSV (Comma-Separated Values) es el formato más común de intercambio de datos simple. Excel lo exporta, bases de datos lo generan, APIs lo devuelven. Python tiene un módulo csv integrado que maneja correctamente los casos problemáticos: comas dentro de valores entrecomillados, saltos de línea, caracteres especiales.

1import csv
2
3# Primero creamos un CSV de ejemplo
4with open("ventas.csv", "w", encoding="utf-8", newline="") as f:
5 writer = csv.writer(f)
6 writer.writerow(["fecha", "producto", "cantidad", "precio"])
7 writer.writerow(["2024-01-15", "Laptop Pro", 2, 1299.99])
8 writer.writerow(["2024-01-15", "Monitor 4K", 1, 449.00])
9 writer.writerow(["2024-01-16", "Teclado mecánico", 5, 89.99])
10 writer.writerow(["2024-01-16", "Ratón ergonómico", 3, 59.99])
11
12# Leer el CSV como lista de diccionarios (DictReader)
13with open("ventas.csv", "r", encoding="utf-8") as f:
14 reader = csv.DictReader(f)
15 ventas = list(reader)
16
17# Ahora ventas es una lista de diccionarios!
18for venta in ventas:
19 total = int(venta["cantidad"]) * float(venta["precio"])
20 print(f"{venta["fecha"]} | {venta["producto"]:20s} | {total:.2f}€")

csv.DictReader convierte un CSV directamente en lista de diccionarios. Perfecto.

Fíjate en algo importante: cuando lees con DictReader, TODOS los valores son strings. "cantidad" no es un int, es "2" como texto. Necesitas convertir explícitamente: int(venta["cantidad"]), float(venta["precio"]). Este es un error clásico de principiante — intentar sumar strings y obtener concatenación en vez de aritmética.

### JSON: el formato de las APIs

JSON (JavaScript Object Notation) es el formato universal de intercambio de datos en la web. Cada API devuelve JSON. Cada configuración moderna usa JSON. Y resulta que JSON se mapea DIRECTAMENTE a listas y diccionarios de Python. Es como si estuvieran hechos el uno para el otro.

1import json
2
3# Datos que queremos guardar
4resumen_diario = {
5 "fecha": "2024-01-15",
6 "total_ventas": 3057.96,
7 "num_transacciones": 4,
8 "productos_top": ["Laptop Pro", "Monitor 4K"],
9 "meta_alcanzada": True,
10}
11
12# Escribir JSON (serializar)
13with open("resumen.json", "w", encoding="utf-8") as f:
14 json.dump(resumen_diario, f, indent=2, ensure_ascii=False)
15
16print("JSON guardado.")
17
18# Leer JSON (deserializar)
19with open("resumen.json", "r", encoding="utf-8") as f:
20 datos = json.load(f)
21
22print(f"Fecha: {datos['fecha']}")
23print(f"Total: {datos['total_ventas']}€")
24print(f"Top: {datos['productos_top']}")

json.dump() escribe y json.load() lee. ensure_ascii=False para acentos.

Consejo de senior: usa indent=2 al escribir JSON durante desarrollo — lo hace legible. En producción, quita el indent para ahorrar espacio (cada archivo puede tener millones de registros). La diferencia de tamaño es significativa a escala.

### Rutas de archivos: el dolor silencioso

Las rutas de archivos son diferentes en Windows y Mac. Windows usa barras invertidas (C:\Users\datos\) y Mac usa barras normales (/Users/datos/). Para evitar problemas, Python tiene el módulo pathlib que maneja rutas de forma independiente del sistema operativo.

1from pathlib import Path
2
3# pathlib funciona igual en Windows y Mac
4ruta_datos = Path("data") / "raw" / "ventas.csv"
5print(ruta_datos) # data/raw/ventas.csv (Mac) o data\raw\ventas.csv (Win)
6
7# Crear directorios si no existen
8ruta_datos.parent.mkdir(parents=True, exist_ok=True)
9
10# Verificar si existe
11if ruta_datos.exists():
12 print(f"Tamaño: {ruta_datos.stat().st_size} bytes")
13else:
14 print("El archivo no existe aún")
15
16# Listar archivos de un directorio
17for archivo in Path("data").glob("*.csv"):
18 print(f"Encontrado: {archivo.name}")

pathlib es la forma moderna y multiplataforma de manejar rutas.

Nunca concatenes rutas con strings ("data/" + "archivo.csv"). Usa pathlib o os.path.join(). Las barras son diferentes en cada SO y los errores son sutiles — tu script funciona en tu Mac pero falla en el servidor Windows del compañero.

Este patrón Leer-Transformar-Escribir es la base de toda ingeniería de datos.

## ejercicios

[01]

Leer CSV y calcular totales

Tienes un CSV con ventas. Léelo con csv.DictReader, calcula el importe total de cada fila (cantidad × precio) y escribe un nuevo CSV con una columna "total" añadida.

Cargando editor...
[02]

Configuración del pipeline en JSON

Crea un archivo config.json con la configuración de un pipeline (ruta de entrada, ruta de salida, umbral de filtro). Luego léelo y usa esos valores para filtrar datos.

Cargando editor...
[03]

Procesar múltiples archivos

Usa pathlib para encontrar todos los archivos .txt en un directorio, leer cada uno, contar las líneas y generar un resumen total.

Cargando editor...

Regístrate para guardar tu progreso.

## comentarios

Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.

Inicia sesión para comentar y responder.

cargando comentarios...