Saltar al contenido principal

7.2.3 Ficheros CSV

El formato CSV (Comma Separated Values) se usa para guardar tablas de datos en texto plano. Es muy habitual para intercambiar información entre Excel, Google Sheets, aplicaciones web y scripts de Python.

Un CSV parece simple, pero tiene reglas importantes (separadores, comillas, saltos de línea) que conviene entender bien.


1️⃣ Qué es un CSV exactamente​

Piensa en un CSV como una tabla:

  • Cada línea es una fila.
  • Cada valor dentro de la línea es una columna.
  • Los valores se separan con un delimitador (normalmente , o ;).

Ejemplo:

Nombre,Edad,Ciudad
Ana,20,Sevilla
Luis,22,Malaga
Por qué usar el módulo csv

Un error común es hacer esto:

linea = '"Apple, Inc.",Cupertino,"1,200.50"'
print(linea.split(","))

Esto rompe datos válidos porque hay comas dentro de comillas.

El módulo csv de Python ya resuelve estos casos correctamente y debe ser la opción por defecto cuando trabajes con CSV reales.


2️⃣ Lectura​

🟩 Lectura básica con csv.reader​

Antes de usar opciones avanzadas, conviene dominar la lectura más directa de un CSV. Con csv.reader recorremos el archivo fila a fila y obtenemos cada registro como una lista de valores.

Lectura simple
import csv

with open("alumnos.csv", "r", encoding="utf-8") as f:
lector = csv.reader(f)
for fila in lector:
print(fila)
en este ejemplo
  • open(..., "r") abre el archivo en modo lectura.
  • csv.reader(f) crea un iterador de filas.
  • Cada fila es una lista de cadenas.
Parámetros útiles en lectura

No todos los CSV usan coma. En muchos entornos (por ejemplo, Excel con configuración regional europea) se usa ;.

lector = csv.reader(f, delimiter=";", quotechar='"')
  • delimiter: separador de columnas (",", ";", etc.).
  • quotechar: carácter que protege textos con separadores internos.

🟦 Lectura con DictReader​

Cuando el CSV tiene cabecera, suele ser mejor leer por nombre de columna.

Lectura por nombres de campo
import csv

with open("ventas.csv", "r", encoding="utf-8") as f:
lector = csv.DictReader(f)
for fila in lector:
print(f"Producto: {fila['Producto']} | Total: {fila['Total']}")
Ventajas prácticas
  • El código es más legible.
  • Evitas errores por índices (fila[2], fila[3], etc.).
  • Si cambia el orden de columnas, el código suele seguir funcionando.

🟨 Comparativa de funcionamiento (reader vs DictReader)​

Criteriocsv.readercsv.DictReader
Tipo de salida por filaListaDiccionario
Acceso a datosPor índice (fila[0])Por nombre (fila["Producto"])
Necesita cabeceraNoSí (o fieldnames)
Legibilidad del códigoMediaAlta
Caso ideal de usoCSV simple o sin cabeceraCSV tabular con cabeceras

3️⃣ Escritura con csv.writer y DictWriter​

Para guardar datos en CSV también hay dos enfoques principales. Igual que en lectura, puedes trabajar con estructuras simples (listas) o con estructuras más expresivas (diccionarios). Elegir uno u otro depende del tipo de datos y de la claridad que necesites en tu código.

🟩 Opción 1: writer (listas)​

csv.writer escribe cada fila como una lista de valores en orden.

Escritura con listas
import csv

filas = [
["Nombre", "Nivel", "Mundo"],
["Mario", 10, "1-1"],
["Luigi", 12, "2-4"],
]

with open("partida.csv", "w", newline="", encoding="utf-8") as f:
escritor = csv.writer(f)
escritor.writerows(filas)
en este ejemplo
  • writerow(...) escribe una sola fila.
  • writerows(...) escribe varias filas de una vez (recibe una lista o iterable de filas).
  • Si ya tienes todos los datos en una estructura tipo lista de listas, writerows(...) reduce código repetitivo.

🟦 Opción 2: DictWriter (diccionarios)​

csv.DictWriter permite escribir por nombre de campo, lo que aporta más legibilidad y control.

Escritura con diccionarios
import csv

cabecera = ["Nombre", "Nivel", "Mundo"]
personajes = [
{"Nombre": "Mario", "Nivel": 10, "Mundo": "1-1"},
{"Nombre": "Luigi", "Nivel": 12, "Mundo": "2-4"},
]

with open("partida.csv", "w", newline="", encoding="utf-8") as f:
escritor = csv.DictWriter(f, fieldnames=cabecera)
escritor.writeheader()
escritor.writerows(personajes)
writeheader() y writerows() con DictWriter
  • writeheader() escribe la primera línea con los nombres de columna definidos en fieldnames.
  • Es recomendable llamarlo una vez al principio para que el CSV quede autodescriptivo.
  • writerows(...) escribe todas las filas de diccionarios respetando el orden de fieldnames.

🟨 Comparativa de funcionamiento (writer vs DictWriter)​

Criteriocsv.writercsv.DictWriter
Tipo de entradaLista de listasLista de diccionarios
Referencia de columnasPor posiciónPor nombre (fieldnames)
Cabecera automáticaNoSí (writeheader())
Riesgo por cambio de ordenMás altoMás bajo
Caso ideal de usoDatos simples y orden fijoDatos tabulares con esquema claro
Uso de newline=""

En Windows, si no usas newline="" al escribir CSV, pueden aparecer líneas en blanco extra.


4️⃣ Ejemplo completo: leer, transformar y guardar​

Este ejemplo une todo lo anterior en un flujo único. La idea es que puedas reutilizar este patrón en casi cualquier tarea básica de CSV.

Pipeline CSV básico
import csv

entradas = []

with open("notas.csv", "r", encoding="utf-8") as f:
lector = csv.DictReader(f)
for fila in lector:
fila["Nota"] = float(fila["Nota"])
fila["Aprobado"] = "SI" if fila["Nota"] >= 5 else "NO"
entradas.append(fila)

with open("notas_resultado.csv", "w", newline="", encoding="utf-8") as f:
campos = ["Alumno", "Nota", "Aprobado"]
escritor = csv.DictWriter(f, fieldnames=campos)
escritor.writeheader()
escritor.writerows(entradas)

Este patrón (leer -> procesar -> escribir) es el flujo más común en tareas de persistencia con CSV.


✅ Buenas prácticas recomendadas​

buenas prácticas
  • Usa siempre with open(...) para cerrar el archivo automáticamente.
  • Indica encoding="utf-8" para evitar problemas con caracteres especiales.
  • Prefiere DictReader/DictWriter cuando trabajes con tablas con cabeceras.
  • Valida datos antes de convertir tipos (int, float, etc.) para evitar errores silenciosos.

🧪 Ejercicios prácticos – Operación Mercurio​

Tras la auditoría de logs de la unidad anterior, el equipo necesita pasar al siguiente nivel: generar y consumir reportes CSV para el panel de analítica.

Tu misión será leer datos comerciales y de usuarios, validarlos y producir nuevos ficheros CSV listos para explotación.

Dispones de estos ficheros: 👉 Descárgalos aquí

  • ventas_global.csv -> ventas generales del sistema
  • ventas_europa.csv -> ventas con formato europeo (; y decimal con coma)
  • usuarios_plataforma.csv -> estado de usuarios del sistema

🟢 Fase 1 – Lectura e inspección inicial​

🟩 Ejercicio 1 – Lectura base de ventas (ventas_global.csv)​

Lee el archivo con csv.reader y muestra:

  • Número total de filas de datos (sin cabecera).
  • Primera venta registrada.
  • Última venta registrada.

Objetivo: practicar lectura secuencial con listas.

🟦 Ejercicio 2 – Lectura con formato europeo (ventas_europa.csv)​

Procesa el fichero usando:

  • delimiter=";"
  • Conversión de PrecioUnitario de texto con coma decimal a float real.

Muestra por pantalla el total de facturación europea.

Objetivo: manejar dialectos y transformación de tipos en CSV.

🟡 Fase 2 – Lectura estructurada y validación​

🟨 Ejercicio 3 – Facturación por canal con DictReader (ventas_global.csv)​

Usando csv.DictReader, calcula la facturación total por canal (Web, Tienda, App).

Condiciones:

  • Convierte Unidades a int.
  • Convierte PrecioUnitario a float.
  • Acumula en un diccionario, por ejemplo: {"Web": 1200.0, "Tienda": 800.0, "App": 500.0}.

Objetivo: trabajar con lectura por nombre de campo.

🟧 Ejercicio 4 – Detección de registros inconsistentes (usuarios_plataforma.csv)​

Detecta y cuenta registros problemáticos:

  • Usuario marcado como activo=True con ultimo_acceso vacío.
  • Filas sin id o sin nombre.

Muestra:

  • Total de registros inconsistentes.
  • 2 ejemplos de líneas problemáticas.

Objetivo: validar calidad de datos antes de escribir nuevos CSV.

🔵 Fase 3 – Escritura de reportes CSV​

🟥 Ejercicio 5 – Resumen por categoría con writer (resumen_categorias.csv)​

Genera un nuevo CSV con esta estructura:

Categoria,UnidadesTotales,FacturacionTotal

Condiciones:

  • Usa csv.writer.
  • Escribe primero la cabecera con writerow(...).
  • Escribe el resto con writerows(...).

Objetivo: practicar escritura basada en listas y control manual de columnas.

🟫 Ejercicio 6 – Exportación de usuarios activos con DictWriter (usuarios_activos.csv)​

Crea un fichero con solo usuarios válidos y activos (activo=True y ultimo_acceso no vacío).

Columnas obligatorias:

  • id
  • nombre
  • rol
  • ultimo_acceso

Condiciones:

  • Usa csv.DictWriter.
  • Define fieldnames.
  • Escribe cabecera con writeheader().

Objetivo: consolidar escritura por diccionarios con esquema fijo.

🟪 Ejercicio 7 – Comparativa de salida (writer vs DictWriter)​

Genera dos archivos con el mismo contenido (top 3 productos por unidades vendidas):

  • top_productos_writer.csv (con csv.writer)
  • top_productos_dictwriter.csv (con csv.DictWriter)

Después, verifica que:

  • Tienen la misma cantidad de filas.
  • Contienen la misma información (aunque cambie el enfoque de escritura).

Objetivo: entender en práctica cuándo usar cada herramienta.

🔴 Fase Final – Entrega del informe​

🟪 Ejercicio 8 – Informe de cierre (informe_csv.txt)​

Genera un informe final en texto plano que incluya:

  • Total de ventas procesadas en ventas_global.csv.
  • Facturación total global.
  • Facturación total europea.
  • Número de registros inconsistentes de usuarios.
  • Número de usuarios activos exportados.

Formato sugerido:

Ventas globales procesadas: X
Facturación global: XXXX.XX
Facturación europea: XXXX.XX
Registros inconsistentes: X
Usuarios activos exportados: X