Python

Python

Tutorial Python: Módulo csv

Domina el módulo csv de Python para leer, escribir y gestionar archivos CSV con dialectos personalizados y manejo avanzado de datos.

Aprende Python y certifícate

Lectura de archivos CSV

El formato CSV (Comma-Separated Values) es uno de los formatos más comunes para almacenar datos tabulares. Python incluye el módulo csv en su biblioteca estándar, que proporciona herramientas eficientes para leer, procesar y analizar archivos CSV sin necesidad de instalar bibliotecas externas.

Fundamentos de la lectura de archivos CSV

Para leer un archivo CSV en Python, primero necesitamos importar el módulo csv y abrir el archivo utilizando la función open():

import csv

with open('datos.csv', 'r', newline='', encoding='utf-8') as archivo:
    # Operaciones de lectura

Observa los parámetros utilizados:

  • El parámetro 'r' indica que abrimos el archivo en modo lectura
  • newline='' evita problemas con diferentes interpretaciones de saltos de línea en distintos sistemas operativos
  • encoding='utf-8' especifica la codificación del archivo para manejar correctamente caracteres especiales

Utilizando el lector CSV básico

El módulo csv proporciona la clase reader que nos permite iterar sobre las filas del archivo CSV:

import csv

with open('contactos.csv', 'r', newline='', encoding='utf-8') as archivo:
    lector_csv = csv.reader(archivo)
    
    # Leer la primera fila como encabezados
    encabezados = next(lector_csv)
    print(f"Columnas: {encabezados}")
    
    # Leer el resto de filas
    for fila in lector_csv:
        print(fila)

Cada fila se devuelve como una lista de cadenas. Si nuestro archivo contactos.csv contiene:

nombre,email,telefono
Ana García,ana@ejemplo.com,612345678
Carlos López,carlos@ejemplo.com,698765432

El código anterior mostraría:

Columnas: ['nombre', 'email', 'telefono']
['Ana García', 'ana@ejemplo.com', '612345678']
['Carlos López', 'carlos@ejemplo.com', '698765432']

Utilizando DictReader para acceso por nombre de columna

Una forma más conveniente de trabajar con archivos CSV es utilizando csv.DictReader, que devuelve cada fila como un diccionario donde las claves son los nombres de las columnas:

import csv

with open('productos.csv', 'r', newline='', encoding='utf-8') as archivo:
    lector_dict = csv.DictReader(archivo)
    
    # Imprimir los nombres de las columnas
    print(f"Columnas: {lector_dict.fieldnames}")
    
    # Procesar cada fila como un diccionario
    for fila in lector_dict:
        print(f"Producto: {fila['nombre']}, Precio: {fila['precio']}€, Stock: {fila['stock']}")

Si nuestro archivo productos.csv contiene:

nombre,precio,stock
Teclado mecánico,89.99,15
Monitor 24",159.95,8
Ratón inalámbrico,29.99,22

El código mostraría:

Columnas: ['nombre', 'precio', 'stock']
Producto: Teclado mecánico, Precio: 89.99€, Stock: 15
Producto: Monitor 24", Precio: 159.95€, Stock: 8
Producto: Ratón inalámbrico, Precio: 29.99€, Stock: 22

La ventaja de DictReader es que podemos acceder a los valores por el nombre de la columna, lo que hace el código más legible y menos propenso a errores si cambia el orden de las columnas.

Manejo de delimitadores personalizados

No todos los archivos CSV utilizan comas como separadores. Algunos utilizan punto y coma (;), tabulaciones (\t) u otros caracteres. Podemos especificar el delimitador al crear el lector:

import csv

# Para archivos que usan punto y coma como separador (común en países europeos)
with open('datos_europeos.csv', 'r', newline='', encoding='utf-8') as archivo:
    lector = csv.reader(archivo, delimiter=';')
    for fila in lector:
        print(fila)

# Para archivos TSV (valores separados por tabulaciones)
with open('datos.tsv', 'r', newline='', encoding='utf-8') as archivo:
    lector = csv.reader(archivo, delimiter='\t')
    for fila in lector:
        print(fila)

Conversión de tipos de datos

El módulo csv siempre devuelve los datos como cadenas de texto, incluso para valores numéricos. A menudo necesitaremos convertir estos valores a tipos de datos apropiados:

import csv

with open('ventas.csv', 'r', newline='', encoding='utf-8') as archivo:
    lector = csv.DictReader(archivo)
    
    total_ventas = 0
    for fila in lector:
        # Convertir el precio de string a float
        precio = float(fila['precio'])
        # Convertir la cantidad de string a int
        cantidad = int(fila['cantidad'])
        
        subtotal = precio * cantidad
        total_ventas += subtotal
        
        print(f"Producto: {fila['producto']}, Subtotal: {subtotal:.2f}€")
    
    print(f"Total de ventas: {total_ventas:.2f}€")

Manejo de errores comunes

Al trabajar con archivos CSV, es importante manejar posibles errores:

import csv
import os

nombre_archivo = 'datos.csv'

try:
    # Verificar si el archivo existe
    if not os.path.exists(nombre_archivo):
        raise FileNotFoundError(f"El archivo {nombre_archivo} no existe")
    
    with open(nombre_archivo, 'r', newline='', encoding='utf-8') as archivo:
        try:
            lector = csv.reader(archivo)
            for fila in lector:
                # Verificar si la fila tiene el número esperado de columnas
                if len(fila) < 3:
                    print(f"Advertencia: La fila {lector.line_num} no tiene suficientes columnas")
                    continue
                
                print(fila)
        except csv.Error as e:
            print(f"Error al procesar el CSV en la línea {lector.line_num}: {e}")
except Exception as e:
    print(f"Error: {e}")

Filtrado y procesamiento de datos

Una tarea común es filtrar y procesar datos de un archivo CSV:

import csv

with open('empleados.csv', 'r', newline='', encoding='utf-8') as archivo:
    lector = csv.DictReader(archivo)
    
    # Filtrar empleados del departamento de Tecnología con salario > 50000
    empleados_filtrados = [
        empleado for empleado in lector
        if empleado['departamento'] == 'Tecnología' and float(empleado['salario']) > 50000
    ]
    
    # Ordenar por salario (de mayor a menor)
    empleados_ordenados = sorted(
        empleados_filtrados, 
        key=lambda emp: float(emp['salario']), 
        reverse=True
    )
    
    # Mostrar resultados
    print(f"Empleados de Tecnología con salario > 50000€ (ordenados por salario):")
    for empleado in empleados_ordenados:
        print(f"{empleado['nombre']}: {empleado['salario']}€")

Análisis básico de datos CSV

Podemos realizar análisis básicos de datos directamente con el módulo csv:

import csv
from collections import Counter

with open('ventas_regionales.csv', 'r', newline='', encoding='utf-8') as archivo:
    lector = csv.DictReader(archivo)
    
    # Extraer datos para análisis
    ventas_por_region = {}
    productos_vendidos = Counter()
    
    for fila in lector:
        region = fila['region']
        producto = fila['producto']
        cantidad = int(fila['cantidad'])
        
        # Acumular ventas por región
        if region not in ventas_por_region:
            ventas_por_region[region] = 0
        ventas_por_region[region] += cantidad
        
        # Contar productos vendidos
        productos_vendidos[producto] += cantidad
    
    # Mostrar resultados
    print("Ventas por región:")
    for region, total in sorted(ventas_por_region.items(), key=lambda x: x[1], reverse=True):
        print(f"{region}: {total} unidades")
    
    print("\nProductos más vendidos:")
    for producto, cantidad in productos_vendidos.most_common(3):
        print(f"{producto}: {cantidad} unidades")

Conversión entre CSV y estructuras de datos Python

Podemos convertir fácilmente datos CSV a estructuras de datos Python y viceversa:

import csv

# Convertir CSV a lista de diccionarios
def csv_a_lista_dict(nombre_archivo):
    with open(nombre_archivo, 'r', newline='', encoding='utf-8') as archivo:
        return list(csv.DictReader(archivo))

# Convertir CSV a lista de listas
def csv_a_lista_listas(nombre_archivo):
    with open(nombre_archivo, 'r', newline='', encoding='utf-8') as archivo:
        lector = csv.reader(archivo)
        return list(lector)

# Ejemplo de uso
datos_dict = csv_a_lista_dict('datos.csv')
print(f"Primer registro como diccionario: {datos_dict[0]}")

datos_lista = csv_a_lista_listas('datos.csv')
print(f"Encabezados: {datos_lista[0]}")
print(f"Primera fila de datos: {datos_lista[1]}")

Esta función nos permite cargar todo el contenido de un archivo CSV en memoria para procesarlo con las potentes herramientas de manipulación de datos de Python, como comprensiones de listas, funciones map(), filter(), etc.

Escritura de archivos CSV

Así como Python facilita la lectura de archivos CSV, también proporciona herramientas eficientes para crear y escribir datos en este formato. La escritura de archivos CSV es fundamental cuando necesitamos exportar resultados de análisis, generar informes o compartir datos con otros sistemas.

Fundamentos de la escritura de archivos CSV

Para escribir en un archivo CSV, utilizamos el módulo csv con la función open() en modo escritura:

import csv

with open('nuevo_archivo.csv', 'w', newline='', encoding='utf-8') as archivo:
    # Operaciones de escritura

Los parámetros clave son:

  • 'w' indica modo escritura (sobrescribe el archivo si existe)
  • newline='' evita la inserción de líneas en blanco adicionales
  • encoding='utf-8' garantiza la correcta codificación de caracteres especiales

Escritura básica con csv.writer

La clase writer permite escribir datos en formato CSV de manera sencilla:

import csv

# Datos a escribir
datos = [
    ['Nombre', 'Edad', 'Ciudad'],  # Encabezados
    ['Elena Martínez', 28, 'Madrid'],
    ['Pablo Sánchez', 34, 'Barcelona'],
    ['Laura Gómez', 31, 'Valencia']
]

with open('personas.csv', 'w', newline='', encoding='utf-8') as archivo:
    escritor = csv.writer(archivo)
    
    # Escribir todas las filas de una vez
    escritor.writerows(datos)
    
    # Alternativamente, podemos escribir fila por fila:
    # for fila in datos:
    #     escritor.writerow(fila)

El archivo resultante personas.csv contendrá:

Nombre,Edad,Ciudad
Elena Martínez,28,Madrid
Pablo Sánchez,34,Barcelona
Laura Gómez,31,Valencia

Escritura con csv.DictWriter

Para una escritura más intuitiva, especialmente cuando trabajamos con diccionarios, podemos usar csv.DictWriter:

import csv

# Datos como lista de diccionarios
productos = [
    {'id': 1001, 'nombre': 'Portátil ultraligero', 'precio': 899.99, 'stock': 12},
    {'id': 1002, 'nombre': 'Tablet 10"', 'precio': 349.50, 'stock': 25},
    {'id': 1003, 'nombre': 'Smartphone premium', 'precio': 749.00, 'stock': 8}
]

# Definir los campos (columnas) que queremos incluir
campos = ['id', 'nombre', 'precio', 'stock']

with open('inventario.csv', 'w', newline='', encoding='utf-8') as archivo:
    escritor = csv.DictWriter(archivo, fieldnames=campos)
    
    # Escribir la fila de encabezados
    escritor.writeheader()
    
    # Escribir los datos
    escritor.writerows(productos)

El archivo inventario.csv resultante contendrá:

id,nombre,precio,stock
1001,Portátil ultraligero,899.99,12
1002,"Tablet 10""",349.5,25
1003,Smartphone premium,749.0,8

Observa cómo el módulo csv maneja automáticamente el escapado de comillas en el texto "Tablet 10"".

Añadir datos a un archivo existente

Para añadir datos a un archivo CSV existente sin sobrescribirlo, usamos el modo 'a' (append):

import csv
import os

nuevo_producto = ['1004', 'Auriculares inalámbricos', '89.95', '30']

with open('inventario.csv', 'a', newline='', encoding='utf-8') as archivo:
    escritor = csv.writer(archivo)
    escritor.writerow(nuevo_producto)

Si necesitamos verificar si el archivo ya existe para decidir si escribir los encabezados:

import csv
import os

archivo_existe = os.path.isfile('ventas_mensuales.csv')

with open('ventas_mensuales.csv', 'a', newline='', encoding='utf-8') as archivo:
    campos = ['fecha', 'producto', 'cantidad', 'precio_unitario', 'total']
    escritor = csv.DictWriter(archivo, fieldnames=campos)
    
    # Escribir encabezados solo si el archivo es nuevo
    if not archivo_existe:
        escritor.writeheader()
    
    # Añadir nueva venta
    nueva_venta = {
        'fecha': '2023-11-15',
        'producto': 'Monitor curvo 32"',
        'cantidad': 2,
        'precio_unitario': 299.99,
        'total': 599.98
    }
    
    escritor.writerow(nueva_venta)

Personalización del formato de salida

Podemos personalizar varios aspectos del formato CSV de salida:

import csv

datos = [
    ['Producto', 'Descripción', 'Precio'],
    ['Cafetera', 'Cafetera automática con molinillo integrado', 249.99],
    ['Batidora', 'Batidora de vaso de alta potencia', 89.95],
    ['Tostadora', 'Tostadora de 2 ranuras con control de temperatura', 45.50]
]

with open('catalogo.csv', 'w', newline='', encoding='utf-8') as archivo:
    escritor = csv.writer(
        archivo,
        delimiter=';',       # Usar punto y coma como separador
        quotechar='"',       # Carácter para entrecomillar texto
        quoting=csv.QUOTE_MINIMAL  # Entrecomillar solo cuando sea necesario
    )
    
    escritor.writerows(datos)

El archivo catalogo.csv resultante usará punto y coma como separador:

Producto;Descripción;Precio
Cafetera;"Cafetera automática con molinillo integrado";249.99
Batidora;"Batidora de vaso de alta potencia";89.95
Tostadora;"Tostadora de 2 ranuras con control de temperatura";45.5

Las opciones de quoting disponibles son:

  • csv.QUOTE_MINIMAL: Entrecomilla solo campos que contienen el delimitador o el quotechar
  • csv.QUOTE_ALL: Entrecomilla todos los campos
  • csv.QUOTE_NONNUMERIC: Entrecomilla campos no numéricos
  • csv.QUOTE_NONE: No entrecomilla ningún campo

Transformación de datos antes de escribir

A menudo necesitamos transformar o formatear datos antes de escribirlos en un CSV:

import csv
from datetime import datetime

# Datos de transacciones
transacciones = [
    {'id': 'T001', 'fecha': datetime(2023, 11, 10), 'importe': 125.50, 'completada': True},
    {'id': 'T002', 'fecha': datetime(2023, 11, 11), 'importe': 89.99, 'completada': False},
    {'id': 'T003', 'fecha': datetime(2023, 11, 12), 'importe': 250.00, 'completada': True}
]

with open('transacciones.csv', 'w', newline='', encoding='utf-8') as archivo:
    campos = ['id', 'fecha', 'importe', 'estado']
    escritor = csv.DictWriter(archivo, fieldnames=campos)
    
    escritor.writeheader()
    
    for t in transacciones:
        # Transformar datos antes de escribir
        fila = {
            'id': t['id'],
            'fecha': t['fecha'].strftime('%d/%m/%Y'),  # Formatear fecha
            'importe': f"{t['importe']:.2f}",          # Formatear número
            'estado': 'Completada' if t['completada'] else 'Pendiente'  # Texto descriptivo
        }
        escritor.writerow(fila)

El archivo resultante tendrá los datos formateados:

id,fecha,importe,estado
T001,10/11/2023,125.50,Completada
T002,11/11/2023,89.99,Pendiente
T003,12/11/2023,250.00,Completada

Exportación de estructuras de datos a CSV

Podemos exportar fácilmente estructuras de datos Python a archivos CSV:

import csv

# Convertir una lista de diccionarios a CSV
def lista_dict_a_csv(datos, nombre_archivo, campos=None):
    # Si no se especifican campos, usar las claves del primer diccionario
    if campos is None and datos:
        campos = datos[0].keys()
    
    with open(nombre_archivo, 'w', newline='', encoding='utf-8') as archivo:
        escritor = csv.DictWriter(archivo, fieldnames=campos)
        escritor.writeheader()
        escritor.writerows(datos)

# Ejemplo: exportar resultados de análisis
resultados_analisis = [
    {'muestra': 'A1', 'ph': 7.2, 'temperatura': 22.5, 'contaminantes': 'No'},
    {'muestra': 'B2', 'ph': 6.8, 'temperatura': 23.1, 'contaminantes': 'Sí'},
    {'muestra': 'C3', 'ph': 7.5, 'temperatura': 21.8, 'contaminantes': 'No'}
]

# Exportar solo ciertos campos en un orden específico
lista_dict_a_csv(
    resultados_analisis, 
    'resultados_laboratorio.csv',
    campos=['muestra', 'ph', 'temperatura', 'contaminantes']
)

Manejo de errores en la escritura

Es importante implementar un manejo adecuado de errores al escribir archivos CSV:

import csv
import os

def exportar_datos_seguro(datos, ruta_archivo):
    # Crear directorio si no existe
    directorio = os.path.dirname(ruta_archivo)
    if directorio and not os.path.exists(directorio):
        try:
            os.makedirs(directorio)
        except OSError as e:
            return f"Error al crear directorio: {e}"
    
    try:
        with open(ruta_archivo, 'w', newline='', encoding='utf-8') as archivo:
            if not datos:
                return "No hay datos para exportar"
            
            # Determinar campos desde el primer elemento
            campos = datos[0].keys()
            escritor = csv.DictWriter(archivo, fieldnames=campos)
            
            escritor.writeheader()
            escritor.writerows(datos)
            
            return f"Archivo guardado correctamente en {ruta_archivo}"
    except PermissionError:
        return "Error: No tienes permisos para escribir en esta ubicación"
    except IOError as e:
        return f"Error de E/S: {e}"
    except Exception as e:
        return f"Error inesperado: {e}"

# Ejemplo de uso
resultado = exportar_datos_seguro(
    [{'nombre': 'Ana', 'edad': 28}, {'nombre': 'Luis', 'edad': 35}],
    'datos/personal/empleados.csv'
)
print(resultado)

Caso práctico: Exportación de resultados de análisis

Veamos un ejemplo completo de exportación de resultados de análisis a CSV:

import csv
from datetime import datetime

def analizar_ventas(datos_ventas):
    """Analiza datos de ventas y devuelve estadísticas"""
    if not datos_ventas:
        return []
    
    # Agrupar ventas por producto
    ventas_por_producto = {}
    for venta in datos_ventas:
        producto = venta['producto']
        cantidad = int(venta['cantidad'])
        importe = float(venta['importe'])
        
        if producto not in ventas_por_producto:
            ventas_por_producto[producto] = {'unidades': 0, 'total': 0.0}
        
        ventas_por_producto[producto]['unidades'] += cantidad
        ventas_por_producto[producto]['total'] += importe
    
    # Convertir a lista de resultados
    resultados = []
    for producto, datos in ventas_por_producto.items():
        precio_medio = datos['total'] / datos['unidades'] if datos['unidades'] > 0 else 0
        resultados.append({
            'producto': producto,
            'unidades_vendidas': datos['unidades'],
            'importe_total': datos['total'],
            'precio_medio': precio_medio
        })
    
    # Ordenar por importe total (de mayor a menor)
    return sorted(resultados, key=lambda x: x['importe_total'], reverse=True)

# Datos de ejemplo
ventas = [
    {'fecha': '2023-11-01', 'producto': 'Laptop', 'cantidad': '2', 'importe': '1799.98'},
    {'fecha': '2023-11-02', 'producto': 'Monitor', 'cantidad': '3', 'importe': '599.97'},
    {'fecha': '2023-11-02', 'producto': 'Laptop', 'cantidad': '1', 'importe': '899.99'},
    {'fecha': '2023-11-03', 'producto': 'Teclado', 'cantidad': '5', 'importe': '249.95'},
    {'fecha': '2023-11-04', 'producto': 'Monitor', 'cantidad': '2', 'importe': '399.98'}
]

# Analizar datos
resultados_analisis = analizar_ventas(ventas)

# Exportar resultados a CSV
nombre_archivo = f"informe_ventas_{datetime.now().strftime('%Y%m%d')}.csv"

with open(nombre_archivo, 'w', newline='', encoding='utf-8') as archivo:
    campos = ['producto', 'unidades_vendidas', 'importe_total', 'precio_medio']
    escritor = csv.DictWriter(archivo, fieldnames=campos)
    
    escritor.writeheader()
    
    for resultado in resultados_analisis:
        # Formatear valores numéricos antes de escribir
        fila = {
            'producto': resultado['producto'],
            'unidades_vendidas': resultado['unidades_vendidas'],
            'importe_total': f"{resultado['importe_total']:.2f}",
            'precio_medio': f"{resultado['precio_medio']:.2f}"
        }
        escritor.writerow(fila)

print(f"Informe generado: {nombre_archivo}")

Este ejemplo muestra cómo analizar datos de ventas y exportar los resultados a un archivo CSV con un nombre que incluye la fecha actual, facilitando la organización de informes periódicos.

Dialectos y formatos

Cuando trabajamos con archivos CSV, nos encontramos con que no existe un estándar único y universal para este formato. Diferentes aplicaciones, sistemas y regiones utilizan variaciones en la forma de estructurar los datos CSV. El módulo csv de Python aborda esta realidad mediante el concepto de "dialectos", que permite adaptar la lectura y escritura a diferentes formatos CSV.

Entendiendo los dialectos CSV

Un dialecto en el contexto del módulo csv define un conjunto de parámetros que determinan cómo se interpretan o generan los archivos CSV. Estos parámetros incluyen el delimitador, el carácter de comillas, y otras características de formato.

Python incluye varios dialectos predefinidos:

import csv

# Mostrar los dialectos disponibles
print(csv.list_dialects())  # Típicamente muestra: ['excel', 'excel-tab', 'unix']

Los dialectos predefinidos más comunes son:

  • excel: El formato utilizado por Microsoft Excel (delimitador coma, comillas dobles)
  • excel-tab: Similar a excel pero usando tabulaciones como delimitador
  • unix: Un formato más estricto común en sistemas Unix (sin espacios después del delimitador)

Podemos especificar el dialecto al crear lectores o escritores CSV:

import csv

# Leer un archivo usando el dialecto excel
with open('datos.csv', 'r', newline='', encoding='utf-8') as archivo:
    lector = csv.reader(archivo, dialect='excel')
    for fila in lector:
        print(fila)

# Escribir usando el dialecto unix
with open('datos_unix.csv', 'w', newline='', encoding='utf-8') as archivo:
    escritor = csv.writer(archivo, dialect='unix')
    escritor.writerow(['Nombre', 'Edad', 'Ciudad'])
    escritor.writerow(['María', '29', 'Sevilla'])

Propiedades de los dialectos

Cada dialecto define varias propiedades que controlan el formato CSV:

import csv

# Examinar las propiedades del dialecto excel
dialecto = csv.get_dialect('excel')
print(f"Delimitador: '{dialecto.delimiter}'")
print(f"Carácter de comillas: '{dialecto.quotechar}'")
print(f"Estilo de comillas: {dialecto.quoting}")
print(f"Escapador: '{dialecto.escapechar}'")
print(f"Salto de línea: '{dialecto.lineterminator}'")

Las propiedades principales incluyen:

  • delimiter: El carácter usado para separar campos (típicamente ',' o ';')
  • quotechar: El carácter usado para rodear campos que contienen caracteres especiales
  • quoting: Determina cuándo se deben usar comillas (QUOTE_MINIMAL, QUOTE_ALL, etc.)
  • escapechar: Carácter usado para escapar el delimitador o las comillas
  • lineterminator: Secuencia que marca el final de una línea
  • doublequote: Si es True, las comillas dentro de un campo se duplican
  • skipinitialspace: Si es True, se ignoran espacios después del delimitador

Creando dialectos personalizados

Cuando trabajamos con formatos CSV no estándar, podemos crear nuestros propios dialectos:

import csv

# Registrar un nuevo dialecto para archivos europeos (con ; como delimitador)
csv.register_dialect(
    'europeo',
    delimiter=';',
    quotechar='"',
    doublequote=True,
    skipinitialspace=True,
    lineterminator='\r\n',
    quoting=csv.QUOTE_MINIMAL
)

# Usar el dialecto personalizado
with open('ventas_europa.csv', 'w', newline='', encoding='utf-8') as archivo:
    escritor = csv.writer(archivo, dialect='europeo')
    escritor.writerow(['Producto', 'Precio', 'Cantidad'])
    escritor.writerow(['Portátil', '899,99', '5'])  # Nota: coma como separador decimal

Los dialectos personalizados son especialmente útiles cuando necesitamos procesar archivos de diferentes fuentes o generar archivos para sistemas específicos.

Detectando dialectos automáticamente

Python ofrece una función experimental para detectar automáticamente el dialecto de un archivo CSV:

import csv

# Muestra de datos CSV
muestra = '''\
"producto";"precio";"stock"
"Laptop HP";"799,99";"12"
"Monitor Samsung";"349,50";"8"
"Teclado mecánico";"89,95";"15"
'''

# Detectar el dialecto
dialecto = csv.Sniffer().sniff(muestra)
print(f"Delimitador detectado: '{dialecto.delimiter}'")
print(f"Comillas detectadas: '{dialecto.quotechar}'")

# Determinar si tiene encabezados
tiene_encabezados = csv.Sniffer().has_header(muestra)
print(f"¿Tiene encabezados? {tiene_encabezados}")

# Usar el dialecto detectado para leer los datos
import io
lector = csv.reader(io.StringIO(muestra), dialect=dialecto)
for fila in lector:
    print(fila)

Esta funcionalidad es útil cuando recibimos archivos CSV de fuentes desconocidas o variables.

Dialectos para casos específicos

Veamos algunos ejemplos de dialectos para casos específicos:

import csv

# Dialecto para archivos con campos separados por pipes (|)
csv.register_dialect(
    'pipes',
    delimiter='|',
    quotechar='"',
    doublequote=True,
    lineterminator='\n'
)

# Dialecto para CSV sin comillas (útil para datos simples)
csv.register_dialect(
    'sin_comillas',
    delimiter=',',
    quoting=csv.QUOTE_NONE,
    escapechar='\\'
)

# Dialecto que entrecomilla todos los campos
csv.register_dialect(
    'todo_comillas',
    delimiter=',',
    quotechar='"',
    quoting=csv.QUOTE_ALL
)

Trabajando con formatos regionales

Los formatos CSV varían según la región. Por ejemplo, en muchos países europeos:

  • Se usa punto y coma (;) como delimitador de campo
  • Se usa coma (,) como separador decimal

Esto requiere consideraciones especiales:

import csv
import locale

# Configurar locale para formato europeo (opcional)
# locale.setlocale(locale.LC_ALL, 'es_ES.UTF-8')

# Datos de ventas con formato europeo
datos_ventas = [
    ['Producto', 'Precio', 'Cantidad', 'Total'],
    ['Portátil', '899,99', '2', '1799,98'],
    ['Monitor', '249,50', '3', '748,50'],
    ['Teclado', '45,95', '5', '229,75']
]

# Guardar en formato europeo
with open('ventas_formato_europeo.csv', 'w', newline='', encoding='utf-8') as archivo:
    escritor = csv.writer(archivo, delimiter=';')
    escritor.writerows(datos_ventas)

# Leer y convertir a formato numérico Python
with open('ventas_formato_europeo.csv', 'r', newline='', encoding='utf-8') as archivo:
    lector = csv.reader(archivo, delimiter=';')
    encabezados = next(lector)
    
    for fila in lector:
        # Convertir valores con coma decimal a float
        precio = float(fila[1].replace(',', '.'))
        cantidad = int(fila[2])
        total = float(fila[3].replace(',', '.'))
        
        print(f"{fila[0]}: {precio} € x {cantidad} = {total} €")

Preservando dialectos entre sesiones

Si necesitamos mantener consistencia en el formato de nuestros archivos CSV a lo largo del tiempo, podemos guardar la configuración del dialecto:

import csv
import json

# Definir un dialecto personalizado
csv.register_dialect(
    'mi_formato',
    delimiter='|',
    quotechar='"',
    doublequote=True,
    skipinitialspace=True,
    lineterminator='\n',
    quoting=csv.QUOTE_MINIMAL
)

# Guardar la configuración del dialecto
dialecto = csv.get_dialect('mi_formato')
config_dialecto = {
    'delimiter': dialecto.delimiter,
    'quotechar': dialecto.quotechar,
    'doublequote': dialecto.doublequote,
    'skipinitialspace': dialecto.skipinitialspace,
    'lineterminator': dialecto.lineterminator,
    'quoting': dialecto.quoting
}

# Guardar en un archivo de configuración
with open('config_csv.json', 'w', encoding='utf-8') as f:
    json.dump(config_dialecto, f, indent=2)

# En otra sesión, cargar la configuración
with open('config_csv.json', 'r', encoding='utf-8') as f:
    config = json.load(f)
    
# Recrear el dialecto
csv.register_dialect(
    'mi_formato_restaurado',
    delimiter=config['delimiter'],
    quotechar=config['quotechar'],
    doublequote=config['doublequote'],
    skipinitialspace=config['skipinitialspace'],
    lineterminator=config['lineterminator'],
    quoting=config['quoting']
)

Caso práctico: Convertir entre formatos CSV

Un caso de uso común es convertir archivos CSV entre diferentes formatos:

import csv

def convertir_formato_csv(archivo_origen, archivo_destino, dialecto_origen, dialecto_destino):
    """
    Convierte un archivo CSV de un formato a otro.
    
    Args:
        archivo_origen: Ruta al archivo CSV de origen
        archivo_destino: Ruta donde guardar el archivo convertido
        dialecto_origen: Dialecto del archivo de origen
        dialecto_destino: Dialecto para el archivo de destino
    """
    # Leer datos con el dialecto de origen
    with open(archivo_origen, 'r', newline='', encoding='utf-8') as f_origen:
        lector = csv.reader(f_origen, dialect=dialecto_origen)
        datos = list(lector)
    
    # Escribir datos con el dialecto de destino
    with open(archivo_destino, 'w', newline='', encoding='utf-8') as f_destino:
        escritor = csv.writer(f_destino, dialect=dialecto_destino)
        escritor.writerows(datos)
    
    return len(datos)

# Ejemplo: Convertir de formato europeo (;) a formato estándar (,)
csv.register_dialect('europeo', delimiter=';', quotechar='"')

filas_convertidas = convertir_formato_csv(
    'datos_europeos.csv',
    'datos_estandar.csv',
    'europeo',
    'excel'
)

print(f"Conversión completada: {filas_convertidas} filas procesadas")

Trabajando con Excel y otros programas

Aunque el dialecto 'excel' funciona bien para la mayoría de los casos, a veces necesitamos ajustes adicionales para una compatibilidad perfecta:

import csv

# Dialecto optimizado para Excel (incluye BOM para caracteres Unicode)
with open('para_excel.csv', 'w', newline='', encoding='utf-8-sig') as archivo:
    escritor = csv.writer(
        archivo,
        dialect='excel',
        delimiter=',',
        quotechar='"',
        quoting=csv.QUOTE_MINIMAL
    )
    
    escritor.writerow(['Nombre', 'Departamento', 'Salario (€)'])
    escritor.writerow(['José Martínez', 'Desarrollo', 52000])
    escritor.writerow(['Ana García', 'Marketing', 48000])
    escritor.writerow(['Carlos Rodríguez', 'Finanzas', 55000])

El uso de encoding='utf-8-sig' añade una marca de orden de bytes (BOM) que ayuda a Excel a reconocer correctamente los caracteres Unicode.

Resumen de opciones de formato

Para referencia rápida, aquí hay un resumen de las opciones de formato más comunes:

import csv

# Opciones de formato comunes y sus valores
formatos_comunes = {
    'excel_estandar': {
        'delimiter': ',',
        'quotechar': '"',
        'quoting': csv.QUOTE_MINIMAL
    },
    'excel_europeo': {
        'delimiter': ';',
        'quotechar': '"',
        'quoting': csv.QUOTE_MINIMAL
    },
    'tsv': {
        'delimiter': '\t',
        'quotechar': '"',
        'quoting': csv.QUOTE_MINIMAL
    },
    'unix_simple': {
        'delimiter': ',',
        'quotechar': '"',
        'quoting': csv.QUOTE_MINIMAL,
        'lineterminator': '\n'
    },
    'personalizado_seguro': {
        'delimiter': '|',
        'quotechar': '"',
        'quoting': csv.QUOTE_ALL,  # Entrecomilla todos los campos
        'doublequote': True,       # Duplica las comillas internas
        'escapechar': None         # No usa carácter de escape
    }
}

# Registrar estos formatos como dialectos
for nombre, opciones in formatos_comunes.items():
    csv.register_dialect(nombre, **opciones)

Este enfoque permite seleccionar fácilmente el formato adecuado según las necesidades específicas de cada proyecto.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

30 % DE DESCUENTO

Plan mensual

19.00 /mes

13.30 € /mes

Precio normal mensual: 19 €
63 % DE DESCUENTO

Plan anual

10.00 /mes

7.00 € /mes

Ahorras 144 € al año
Precio normal anual: 120 €
Aprende Python online

Ejercicios de esta lección Módulo csv

Evalúa tus conocimientos de esta lección Módulo csv con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Módulo math

Python
Puzzle

Reto herencia

Python
Código

Excepciones

Python
Test

Introducción a Python

Python
Test

Reto variables

Python
Código

Funciones Python

Python
Puzzle

Reto funciones

Python
Código

Módulo datetime

Python
Test

Reto acumulación

Python
Código

Reto estructuras condicionales

Python
Código

Polimorfismo

Python
Test

Módulo os

Python
Test

Reto métodos dunder

Python
Código

Diccionarios

Python
Puzzle

Reto clases y objetos

Python
Código

Reto operadores

Python
Código

Operadores

Python
Test

Estructuras de control

Python
Puzzle

Funciones lambda

Python
Test

Reto diccionarios

Python
Código

Reto función lambda

Python
Código

Encapsulación

Python
Puzzle

Reto coleciones

Python
Proyecto

Reto funciones auxiliares

Python
Código

Crear módulos y paquetes

Python
Puzzle

Módulo datetime

Python
Puzzle

Excepciones

Python
Puzzle

Operadores

Python
Puzzle

Diccionarios

Python
Test

Reto map, filter

Python
Código

Reto tuplas

Python
Código

Proyecto gestor de tareas CRUD

Python
Proyecto

Tuplas

Python
Puzzle

Variables

Python
Puzzle

Tipos de datos

Python
Puzzle

Conjuntos

Python
Test

Reto mixins

Python
Código

Módulo csv

Python
Test

Módulo json

Python
Test

Herencia

Python
Test

Análisis de datos de ventas con Pandas

Python
Proyecto

Reto fechas y tiempo

Python
Proyecto

Reto estructuras de iteración

Python
Código

Funciones

Python
Test

Reto comprehensions

Python
Código

Variables

Python
Test

Reto serialización

Python
Proyecto

Módulo csv

Python
Puzzle

Reto polimorfismo

Python
Código

Polimorfismo

Python
Puzzle

Clases y objetos

Python
Código

Reto encapsulación

Python
Código

Estructuras de control

Python
Test

Importar módulos y paquetes

Python
Test

Módulo math

Python
Test

Funciones lambda

Python
Puzzle

Reto excepciones

Python
Código

Listas

Python
Puzzle

Reto archivos

Python
Proyecto

Encapsulación

Python
Test

Reto conjuntos

Python
Código

Clases y objetos

Python
Test

Instalación de Python y creación de proyecto

Python
Test

Reto listas

Python
Código

Tipos de datos

Python
Test

Crear módulos y paquetes

Python
Test

Tuplas

Python
Test

Herencia

Python
Puzzle

Reto acceso a sistema

Python
Proyecto

Proyecto sintaxis calculadora

Python
Proyecto

Importar módulos y paquetes

Python
Puzzle

Clases y objetos

Python
Puzzle

Módulo os

Python
Puzzle

Listas

Python
Test

Conjuntos

Python
Puzzle

Reto tipos de datos

Python
Código

Reto matemáticas

Python
Proyecto

Módulo json

Python
Puzzle

Todas las lecciones de Python

Accede a todas las lecciones de Python y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Python

Python

Introducción

Instalación Y Creación De Proyecto

Python

Introducción

Tema 2: Tipos De Datos, Variables Y Operadores

Python

Introducción

Instalación De Python

Python

Introducción

Tipos De Datos

Python

Sintaxis

Variables

Python

Sintaxis

Operadores

Python

Sintaxis

Estructuras De Control

Python

Sintaxis

Funciones

Python

Sintaxis

Estructuras Control Iterativo

Python

Sintaxis

Estructuras Control Condicional

Python

Sintaxis

Testing Con Pytest

Python

Sintaxis

Listas

Python

Estructuras De Datos

Tuplas

Python

Estructuras De Datos

Diccionarios

Python

Estructuras De Datos

Conjuntos

Python

Estructuras De Datos

Comprehensions

Python

Estructuras De Datos

Clases Y Objetos

Python

Programación Orientada A Objetos

Excepciones

Python

Programación Orientada A Objetos

Encapsulación

Python

Programación Orientada A Objetos

Herencia

Python

Programación Orientada A Objetos

Polimorfismo

Python

Programación Orientada A Objetos

Mixins Y Herencia Múltiple

Python

Programación Orientada A Objetos

Métodos Especiales (Dunder Methods)

Python

Programación Orientada A Objetos

Composición De Clases

Python

Programación Orientada A Objetos

Funciones Lambda

Python

Programación Funcional

Aplicación Parcial

Python

Programación Funcional

Entrada Y Salida, Manejo De Archivos

Python

Programación Funcional

Decoradores

Python

Programación Funcional

Generadores

Python

Programación Funcional

Paradigma Funcional

Python

Programación Funcional

Composición De Funciones

Python

Programación Funcional

Funciones Orden Superior Map Y Filter

Python

Programación Funcional

Funciones Auxiliares

Python

Programación Funcional

Reducción Y Acumulación

Python

Programación Funcional

Archivos Comprimidos

Python

Entrada Y Salida Io

Entrada Y Salida Avanzada

Python

Entrada Y Salida Io

Archivos Temporales

Python

Entrada Y Salida Io

Contexto With

Python

Entrada Y Salida Io

Módulo Csv

Python

Biblioteca Estándar

Módulo Json

Python

Biblioteca Estándar

Módulo Datetime

Python

Biblioteca Estándar

Módulo Math

Python

Biblioteca Estándar

Módulo Os

Python

Biblioteca Estándar

Módulo Re

Python

Biblioteca Estándar

Módulo Random

Python

Biblioteca Estándar

Módulo Time

Python

Biblioteca Estándar

Módulo Collections

Python

Biblioteca Estándar

Módulo Sys

Python

Biblioteca Estándar

Módulo Statistics

Python

Biblioteca Estándar

Módulo Pickle

Python

Biblioteca Estándar

Módulo Pathlib

Python

Biblioteca Estándar

Importar Módulos Y Paquetes

Python

Paquetes Y Módulos

Crear Módulos Y Paquetes

Python

Paquetes Y Módulos

Entornos Virtuales (Virtualenv, Venv)

Python

Entorno Y Dependencias

Gestión De Dependencias (Pip, Requirements.txt)

Python

Entorno Y Dependencias

Python-dotenv Y Variables De Entorno

Python

Entorno Y Dependencias

Acceso A Datos Con Mysql, Pymongo Y Pandas

Python

Acceso A Bases De Datos

Acceso A Mongodb Con Pymongo

Python

Acceso A Bases De Datos

Acceso A Mysql Con Mysql Connector

Python

Acceso A Bases De Datos

Novedades Python 3.13

Python

Características Modernas

Operador Walrus

Python

Características Modernas

Pattern Matching

Python

Características Modernas

Instalación Beautiful Soup

Python

Web Scraping

Sintaxis General De Beautiful Soup

Python

Web Scraping

Tipos De Selectores

Python

Web Scraping

Web Scraping De Html

Python

Web Scraping

Web Scraping Para Ciencia De Datos

Python

Web Scraping

Autenticación Y Acceso A Recursos Protegidos

Python

Web Scraping

Combinación De Selenium Con Beautiful Soup

Python

Web Scraping

Accede GRATIS a Python y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender cómo leer archivos CSV utilizando csv.reader y csv.DictReader.
  • Aprender a escribir archivos CSV con csv.writer y csv.DictWriter.
  • Manejar delimitadores personalizados y convertir tipos de datos al leer CSV.
  • Conocer el concepto de dialectos para adaptar la lectura y escritura a diferentes formatos CSV.
  • Implementar manejo de errores y realizar análisis básico y transformación de datos CSV.