CSV. Acceso a datos estructurados (I)
Módulo CSV
Antes de nada una aclaración que parece necesaria: cuando hablamos de acceso a datos debemos distinguir entre lo que es acceder al contenido de un archivo y lo que implica acceder a un determinado dato o conjunto de datos que éste contiene. Lo primero implica hacer uso de determinadas tecnologías y lo segundo, además, la aplicación de determinados procesimientos.
En lo que se refiere a esta entrada cabe diferenciar esos procedimientos en el marco de una distinción que resulta de gran interés: la diferencia que implica acceder a datos estructurados y a datos no estructurados. Cuando hablamos, como ahora, de acceder a datos csv estamos planteando acceder a un tipo de documento (extensión .csv) que es de naturaleza estructurada, como lo son también los datos de una base de datos o los datos contenidos en una hoja de cálculo.
El formato .csv es uno de los formatos básicos para el trabajo con Python. Otro es el formato .txt, pero entre ambos existe una diferencia muy importante: los datos .csv están estructurados, mientras que los datos .txt no lo están. El acceso simple a ambos es sumamente sencillo desde Python, pero mientras que sigue siendo sencillo acceder a contenidos concretos de un archivo .csv, no lo es si trabajamos con un archivo .txt. Es este el motivo por el que (despues de hacerlo sobre directorios y archivos) nos planteamos ahora tratar el acceso a los archivos .csv y sus contenidos.
Un archivo .csv (comma-separated values) es una archivo de texto plano que contiene datos tabulares estructurados en filas y columnas separados por comas u otros delimitadores (punto y coma, tabulaciones).
Cada línea del archivo corresponde a una fila en la tabla, y cada valor de esa fila se separa por un delimitador (coma). Dada su simplicidad pueden ser leídos por casi cualquier hoja de cálculo o software de gestión de datos.
Python cuenta con herramientas para trabajar con archivos .csv, empezando por el módulo nativo CSV (que no requiere instalación mediante pip al ser nativo, aunuse ser importado) y siguiendo por Pandas y NumPy. Empezaremos por CSV
El módulo CSV cuenta con clases para leer y escribir datos tabulares en formato CSV y permite escribir y leer este tipo de archivo.
Existen dos enfoques de trabajo de este módulo en el tratamiento que da a los datos del archivo .csv: como listas o como diccionarios.
csv.reader(), enfoque lista en la lectura del archivo csvcsv.writer(), enfoque lista en la escribir en un archivo csvcsv.DictReader(), enfoque diccionario de la lectura de un archivo csvcsv.DictReader(), enfoque diccionario para la escritura en archivos csv
Veamos cómo se concretan ambos enfoques en el manejo de un mismo archivo csv.
import csv
#Acceso al archivo csv
ruta = 'datos\libros2.csv'
with open(ruta, mode='r', encoding='utf-8', newline='') as archivo:
# Creamos el lector enfocado a lista (csv.reader())
lector = csv.reader(archivo, delimiter=',')
# Visualizamos la cabecera de la tabla csv (mediante next())
cabecera = next(lector)
print(f"Listado de nombres de columnas (cabecera): {cabecera}")
# Iteramos sobre las filas mostrando las tres primeras columnas: id, autor y título
for fila in lector:
print(f"Id: {fila[0]}, Autor: {fila[1]}, Título {fila[2]}")
Esta es la forma más básica de acceder a un archivo csv, útil cuando conocemos la estructura de la tabla y el archivo es manejable en términos de tamaño (campos y número de registros), pero también podemos acceder a un registro determinado y a una serie de campos de ese registro haciendo uso de un bucle y de nuestro conocimiento de la estructura de la tabla. Por ejemplo, este segmento de código requiere la declaración previa de un contador (conta = 0) y nos permite acceder al registro nº 5.
#Mostramos un registro determinado y dentro de él dos campos.
#Para ello empleamos la iteración y nuestro conocimiento de la estructura de la tabla
for fila in lector:
conta += 1
if conta == 5:
print(f"Autor: {fila[1]}, Título {fila[2]}")
break
Visto lo anterior, podemos crear un buscador sencillo de registros que funcione a demanda del usuario. Se trata únicamente de un ejercicio de aplicación de la función csv.reader(), entre otras, porque ya veremos que hay algunas cosas interesantes más.
import csv
ruta_archivo = 'datos\libros3.csv'
def buscador_interactivo():
try:
# 1. Abrimos el archivo
with open(ruta_archivo, mode='r', encoding='utf-8', newline='') as archivo:
# Cargamos el lector
lector = csv.reader(archivo)
cabecera = next(lector)
# Convertimos el lector a una lista para poder buscar varias veces. De no hacerlo sólo podríamos buscar un registro.
# La consecuencia es un incremento de la carga de trabajo para la memoria del sistema (el contenido de la lista, ahora en memoria)
datos = list(lector)
total_registros = len(datos)
print(f"--- 🔎 Buscador de registros cargado. ({total_registros} registros disponibles) ---")
while True:
# 2. Solicitar número al usuario
entrada = input("\nIntroduce el número de registro a buscar (o 'salir' para terminar): ")
if entrada.lower() == 'salir':
print("Gracias por usar nuestro buscador de registros.")
break
# 3. Validar que sea un número
try:
objetivo = int(entrada)
except ValueError:
print("❌ Por favor, introduce un número válido.")
continue
# 4. Buscar usando la función enumerate() sobre la lista de datos
# 4.1. 'datos' es nuestro conjunto de filas.
# 4.2. 'start=1' indica el inicio del conteo desde 1 (y no desde 0).
# 4.3. En cada vuelta, 'i' recibe el número de fila y 'fila' recibe los datos. 'i' es el contador automáticos de enumerate()
encontrado = False
for i, fila in enumerate(datos, start=1):
if i == objetivo:
print(f"\n✅ Registro #{i} encontrado:")
# Mostramos cada dato con su nombre de columna
for col, valor in zip(cabecera, fila):
print(f" {col}: {valor}")
encontrado = True
break
if not encontrado:
print(f"⚠️ El registro {objetivo} no existe. El rango es de 1 a {total_registros}.")
except FileNotFoundError:
print(f"❌ Error: No se encontró el archivo '{ruta_archivo}'.")
# Ejecutar el buscador
buscador_interactivo()