Ficheros e interacción con el sistema
Al completar este módulo serás capaz de:
- Leer y escribir archivos de texto
- Trabajar con archivos CSV y JSON
- Manejar rutas y directorios
- Interactuar con el sistema operativo
¿Por qué trabajar con archivos?
Hasta ahora, todos los datos de tus programas desaparecían al cerrar el programa. Las variables viven en la memoria RAM, y cuando el programa termina… ¡puf! Todo se esfuma. Es como si tu programa tuviera amnesia.
Los archivos son la solución a este problema. Son la forma de guardar información de forma permanente: en el disco duro, en una memoria USB, en la nube… Piensa en todas las cosas que necesitan persistir:
- La configuración de una aplicación (preferencias del usuario)
- Los datos que procesas (lista de clientes, productos, transacciones)
- Los resultados de tu programa (informes, logs, exportaciones)
- Los datos de entrada que tu programa necesita leer
En este capítulo aprenderás a leer y escribir archivos de diferentes formatos, navegar por el sistema de archivos, y organizar tus datos de forma profesional.
Lectura y escritura de archivos
Trabajar con archivos en Python es como abrir un libro: puedes leerlo de principio a fin, saltar a una página específica, escribir notas en los márgenes, o incluso crear un libro nuevo desde cero.
Abrir archivos
La función open() abre la “puerta” al archivo. El modo le dice a Python qué quieres hacer con él:
1# Modos de apertura (piensa en ellos como "intenciones")
2# 'r' - Read: "Solo quiero leer" (por defecto)
3# 'w' - Write: "Quiero escribir desde cero" (¡cuidado: borra todo!)
4# 'a' - Append: "Quiero añadir al final" (sin borrar lo existente)
5# 'x' - Exclusive: "Crear nuevo" (error si ya existe)
6
7archivo = open('datos.txt', 'r')
8contenido = archivo.read()
9archivo.close()Es importante cerrar los archivos después de usarlos para liberar recursos. La mejor forma es usar el contexto with.
Usando context managers (with)
Aquí viene un truco muy útil. Imagina que tienes un mayordomo que te abre la puerta, te deja hacer lo que necesitas, y cuando terminas, cierra la puerta automáticamente. Eso es exactamente lo que hace with:
1# Forma recomendada: el archivo se cierra automáticamente
2with open('datos.txt', 'r') as archivo:
3 contenido = archivo.read()
4 print(contenido)
5# Aquí el archivo ya está cerradoMétodos de lectura
¿Cómo prefieres leer un libro? ¿Todo de golpe, página por página, o capítulo por capítulo? Python te da opciones similares. La elección depende del tamaño del archivo: para archivos pequeños, léelo todo de una vez; para archivos enormes, mejor línea por línea.
1# Leer todo el contenido
2with open('datos.txt', 'r') as f:
3 contenido = f.read()
4 print(contenido)
5
6# Leer N caracteres
7with open('datos.txt', 'r') as f:
8 primeros_100 = f.read(100)1# Leer línea por línea
2with open('datos.txt', 'r') as f:
3 linea1 = f.readline() # Primera línea
4 linea2 = f.readline() # Segunda línea
5 print(linea1)
6 print(linea2)1# Leer todas las líneas como lista
2with open('datos.txt', 'r') as f:
3 lineas = f.readlines()
4 for linea in lineas:
5 print(linea.strip()) # strip() quita \n1# Forma más eficiente para archivos grandes
2with open('datos.txt', 'r') as f:
3 for linea in f:
4 print(linea.strip())Métodos de escritura
Escribir es igual de sencillo. Solo recuerda la diferencia crucial: el modo 'w' es como empezar un cuaderno nuevo (borra todo lo anterior), mientras que 'a' es como seguir escribiendo donde lo dejaste.
1# Escribir texto (sobrescribe el archivo - ¡cuidado!)
2with open('salida.txt', 'w') as f:
3 f.write("Primera línea\n")
4 f.write("Segunda línea\n")
5
6# Escribir múltiples líneas
7lineas = ["Línea 1\n", "Línea 2\n", "Línea 3\n"]
8with open('salida.txt', 'w') as f:
9 f.writelines(lineas)
10
11# Añadir al final del archivo
12with open('salida.txt', 'a') as f:
13 f.write("Nueva línea añadida\n")Manejo de codificación
Si trabajas con texto en español (acentos, ñ, ¿, ¡), necesitas especificar la codificación utf-8. Sin ella, podrías ver caracteres extraños como “España” en lugar de “España”.
1# Especificar codificación (SIEMPRE para texto con acentos)
2with open('datos.txt', 'r', encoding='utf-8') as f:
3 contenido = f.read()
4
5# Escribir con codificación
6with open('salida.txt', 'w', encoding='utf-8') as f:
7 f.write("Texto con acentos: España, Ñoño")Trabajar con CSV
¿Has exportado alguna vez una hoja de Excel? Probablemente obtuviste un archivo .csv. CSV significa “Comma Separated Values” (valores separados por comas), y es básicamente una hoja de cálculo guardada como texto plano.
Es el formato universal para intercambiar datos tabulares: lo entiende Excel, Google Sheets, bases de datos, y prácticamente cualquier programa. Si necesitas pasar datos de un sistema a otro, CSV es tu amigo.
Leer archivos CSV
1import csv
2
3# Leer como lista de listas
4with open('datos.csv', 'r', encoding='utf-8') as f:
5 lector = csv.reader(f)
6 for fila in lector:
7 print(fila) # ['columna1', 'columna2', ...]
8
9# Leer como diccionarios (usa la primera fila como cabecera)
10with open('datos.csv', 'r', encoding='utf-8') as f:
11 lector = csv.DictReader(f)
12 for fila in lector:
13 print(fila['nombre'], fila['edad'])Escribir archivos CSV
1import csv
2
3# Escribir desde lista de listas
4datos = [
5 ['nombre', 'edad', 'ciudad'],
6 ['Ana', 25, 'Madrid'],
7 ['Luis', 30, 'Barcelona']
8]
9
10with open('salida.csv', 'w', newline='', encoding='utf-8') as f:
11 escritor = csv.writer(f)
12 escritor.writerows(datos)
13
14# Escribir desde diccionarios
15personas = [
16 {'nombre': 'Ana', 'edad': 25},
17 {'nombre': 'Luis', 'edad': 30}
18]
19
20with open('salida.csv', 'w', newline='', encoding='utf-8') as f:
21 campos = ['nombre', 'edad']
22 escritor = csv.DictWriter(f, fieldnames=campos)
23 escritor.writeheader() # Escribe cabecera
24 escritor.writerows(personas)En Windows, es importante usar newline='' al abrir archivos CSV para evitar líneas en blanco extra.
Trabajar con JSON
JSON es el idioma universal de internet. Cada vez que una app en tu móvil se conecta a un servidor, probablemente están hablando en JSON. También es el formato preferido para archivos de configuración.
¿Lo mejor? La sintaxis de JSON es casi idéntica a los diccionarios de Python. Es como si alguien hubiera diseñado un formato de archivo pensando en Python (aunque en realidad viene de JavaScript).
Leer JSON
1import json
2
3# Desde archivo
4with open('datos.json', 'r', encoding='utf-8') as f:
5 datos = json.load(f)
6 print(datos)
7
8# Desde string
9texto_json = '{"nombre": "Ana", "edad": 25}'
10datos = json.loads(texto_json)
11print(datos['nombre']) # AnaEscribir JSON
1import json
2
3datos = {
4 'nombre': 'Ana',
5 'edad': 25,
6 'hobbies': ['lectura', 'música'],
7 'activo': True
8}
9
10# A archivo
11with open('salida.json', 'w', encoding='utf-8') as f:
12 json.dump(datos, f, indent=2, ensure_ascii=False)
13
14# A string
15texto = json.dumps(datos, indent=2, ensure_ascii=False)
16print(texto)Parámetros útiles:
indent: Indentación para formato legibleensure_ascii=False: Permite caracteres no-ASCII (acentos, ñ)sort_keys=True: Ordena las claves alfabéticamente
Manejo de rutas y directorios
Navegar por el sistema de archivos desde código es como usar el Explorador de Windows o Finder, pero escribiendo comandos. Necesitas saber dónde estás, cómo moverte entre carpetas, y cómo construir rutas a archivos.
Python tiene dos formas de hacerlo: la tradicional (os.path) y la moderna (pathlib). Te enseñaré ambas, pero pathlib es claramente superior y deberías usarla en código nuevo.
Módulo os.path (el veterano)
1import os
2
3# Obtener directorio actual
4print(os.getcwd())
5
6# Construir rutas de forma portable
7ruta = os.path.join('carpeta', 'subcarpeta', 'archivo.txt')
8print(ruta) # carpeta/subcarpeta/archivo.txt (o con \ en Windows)
9
10# Información de rutas
11ruta = '/home/usuario/documento.txt'
12print(os.path.dirname(ruta)) # /home/usuario
13print(os.path.basename(ruta)) # documento.txt
14print(os.path.splitext(ruta)) # ('/home/usuario/documento', '.txt')
15
16# Verificar existencia
17print(os.path.exists('archivo.txt'))
18print(os.path.isfile('archivo.txt'))
19print(os.path.isdir('carpeta'))Módulo pathlib (el moderno y elegante)
pathlib trata las rutas como objetos inteligentes que “saben” cosas sobre sí mismos. En lugar de llamar funciones pasando strings, creas un objeto Path y le preguntas directamente. Es mucho más intuitivo:
1from pathlib import Path
2
3# Crear objeto Path
4ruta = Path('carpeta') / 'subcarpeta' / 'archivo.txt'
5print(ruta)
6
7# Directorio actual
8actual = Path.cwd()
9home = Path.home()
10
11# Propiedades
12archivo = Path('/home/usuario/documento.txt')
13print(archivo.name) # documento.txt
14print(archivo.stem) # documento
15print(archivo.suffix) # .txt
16print(archivo.parent) # /home/usuario
17
18# Verificaciones
19print(archivo.exists())
20print(archivo.is_file())
21print(archivo.is_dir())
22
23# Leer/escribir directamente
24contenido = Path('datos.txt').read_text(encoding='utf-8')
25Path('salida.txt').write_text('Contenido', encoding='utf-8')Operaciones con directorios
Crear carpetas, listar contenido, buscar archivos… las tareas típicas que harías manualmente en el explorador de archivos.
1import os
2from pathlib import Path
3
4# Crear directorio
5os.makedirs('nueva/carpeta', exist_ok=True)
6# o con pathlib
7Path('nueva/carpeta').mkdir(parents=True, exist_ok=True)
8
9# Listar contenido
10for elemento in os.listdir('.'):
11 print(elemento)
12
13# Con pathlib (más potente)
14for elemento in Path('.').iterdir():
15 if elemento.is_file():
16 print(f"Archivo: {elemento}")
17
18# Buscar archivos con patrón
19for archivo in Path('.').glob('*.txt'):
20 print(archivo)
21
22# Buscar recursivamente
23for archivo in Path('.').rglob('*.py'):
24 print(archivo)Copiar, mover, eliminar
Con gran poder viene gran responsabilidad. Estas operaciones pueden destruir datos si no tienes cuidado. A diferencia de cuando borras algo manualmente (que va a la papelera), aquí la eliminación es permanente.
1import shutil
2import os
3from pathlib import Path
4
5# Copiar archivo
6shutil.copy('origen.txt', 'destino.txt')
7
8# Copiar directorio completo
9shutil.copytree('carpeta_origen', 'carpeta_destino')
10
11# Mover/renombrar
12shutil.move('viejo.txt', 'nuevo.txt')
13# o con pathlib
14Path('viejo.txt').rename('nuevo.txt')
15
16# Eliminar archivo
17os.remove('archivo.txt')
18# o con pathlib
19Path('archivo.txt').unlink()
20
21# Eliminar directorio vacío
22os.rmdir('carpeta_vacia')
23
24# Eliminar directorio con contenido
25shutil.rmtree('carpeta_con_archivos')shutil.rmtree() elimina todo el contenido de forma irreversible. Siempre verifica la ruta antes de usarlo.
Manejo de excepciones con archivos
Los archivos son una fuente común de errores: el archivo no existe, no tienes permisos, el disco está lleno… Tu código debe estar preparado para estas situaciones.
1from pathlib import Path
2
3try:
4 with open('archivo_inexistente.txt', 'r') as f:
5 contenido = f.read()
6except FileNotFoundError:
7 print("El archivo no existe")
8except PermissionError:
9 print("No tienes permisos para leer el archivo")
10except IOError as e:
11 print(f"Error de E/S: {e}")
12
13# Verificar antes de abrir
14archivo = Path('datos.txt')
15if archivo.exists():
16 contenido = archivo.read_text()
17else:
18 print("Archivo no encontrado")¿Qué formato usar?
Con tantas opciones, es normal preguntarse cuál elegir. Aquí tienes una guía práctica:
| Tipo de datos | Formato recomendado | ¿Por qué? |
|---|---|---|
| Tabla simple (filas y columnas) | CSV | Fácil de abrir en Excel, ligero |
| Datos estructurados/anidados | JSON | Soporta listas dentro de listas, diccionarios anidados |
| Texto sin formato | .txt | Simple, universal |
| Configuración de aplicación | JSON | Legible, soporta tipos de datos |
| Logs/registros | .txt o .log | Fácil de añadir líneas (‘a’ mode) |
| Intercambio con APIs web | JSON | Es el estándar de facto |
Si tus datos parecen una hoja de cálculo (filas con las mismas columnas), usa CSV. Si tus datos tienen estructura variable (objetos con diferentes campos, listas anidadas), usa JSON.
Ejercicios prácticos
Crea un programa que lea un archivo de texto y muestre:
- Número total de líneas
- Número total de palabras
- Las 5 palabras más frecuentes
Escribe una función que convierta un archivo CSV a JSON.
Crea un script que organice archivos de una carpeta en subcarpetas según su extensión.