Aprende leyendo en orden

Entrada/salida de archivos — Lee y escribe seguro con with open()

Aprende la entrada/salida de archivos en Python. with open() con cierre automático, diferencias entre read / readlines / readline, modos w / a y el patrón leer-procesar-escribir que guarda en otro archivo — práctica incluida.

La mayoría de los datos con los que trabajan los programas viven en disco como archivos. Leer una lista de tareas, añadir a un log, cargar una configuración — todas son operaciones del día a día.

En Python, with open() te deja hacer esto en una sola unidad sintáctica segura. Este artículo cubre la forma básica de with open(), los tres métodos de lectura (read / readlines / readline), la escritura (w) y la adición (a), y el manejo de rutas con directorios — ejecutando código real contra archivos.

with open() abre y cierra archivos de forma segura

Abrir un archivo es una operación que hace que el SO retenga un recurso, y una vez abierto, debes cerrarlo. Olvidarlo provoca agotamiento de descriptores de archivo, o que los datos a escribir queden atrapados en buffers y nunca lleguen al disco.

Abrir reserva un recurso del SO — cerrar es el contrato
open()el SO asignaFDread / writeclose()liberaopen()el SO asignaFDread / writeolvidaste cerrar-> FD agotados+ buffers sin volcarnormal
open() hace que el SO asigne un descriptor de archivo (FD). Hasta close(), el FD queda retenido y las escrituras se quedan en buffer, sin volcar. Olvidar cerrar es una fuga grave de recursos.

¿Qué es un descriptor de archivo (FD)?

FD (file descriptor) es el ID entero que el SO asigna a cada archivo abierto en este momento. Cada open() reparte un nuevo FD; close() lo devuelve al SO. El SO impone un límite máximo por proceso (en Linux, alrededor de 1.024 por defecto). Al alcanzar ese límite, los nuevos open() empiezan a fallar con OSError: Too many open files. El peligro de olvidar cerrar es exactamente este: retener para siempre un recurso finito.

Escribe la forma with open(path, mode) as f: y el archivo se cierra automáticamente en el momento en que sales del bloque, así que es imposible cometer el error. La f en as f es la variable que recibe el objeto archivo; dentro del bloque with, lees y escribes a través de f.

Las rutas usan barras inclinadas / para separar directorios. open("data/tasks.txt", "r") abre tasks.txt dentro de la carpeta data bajo el directorio actual. Incluso en Windows, la convención de Python usa / — internamente se traduce según el SO.

Flujo de with open()
with open(path, mode)enlazacomo fllama f.read()o f.write()cierreautomáticosale del bloque
Entrar en el with abre el archivo y lo enlaza a as f. Al salir del bloque — normal o por excepción — close() corre automáticamente.

Lectura — read / readlines / readline

Para leer un archivo, usa r (read) como segundo argumento de open(path, "r"). El objeto archivo devuelto tiene tres métodos de lectura para necesidades distintas.

- f.read() — lee el archivo completo como una sola cadena.

- f.readlines() — lo lee como una lista de líneas (cadenas).

- f.readline() — lee una línea. Llamadas repetidas avanzan a la siguiente línea; una cadena vacía "" señala fin de archivo.

Lo que devuelven los tres métodos de lectura
f.read()f.readlines()f.readline()una strtexto completolista delíneasuna str(siguiente llamada =siguiente línea)
read devuelve una cadena, readlines devuelve una lista, readline devuelve una cadena por llamada. Elige según el tamaño del dato.
# Obtener todo el archivo como una sola cadena
with open("data/tasks.txt", "r") as f:
    content = f.read()
print(type(content))     # <class 'str'>

# Obtener una lista de líneas
with open("data/tasks.txt", "r") as f:
    lines = f.readlines()
print(type(lines))       # <class 'list'>

# Obtener una línea cada vez (siguiente llamada -> siguiente línea)
with open("data/tasks.txt", "r") as f:
    first  = f.readline()   # "Escribir el informe\n"
    second = f.readline()   # "Responder correos\n"

A partir de aquí, la consola corre en un sistema de archivos virtual (VFS) en el navegador

La consola de la derecha es un sistema de archivos virtual en el navegador — los archivos como data/tasks.txt ya están preparados para ti. Para ejecutar el mismo código en tu PC local, crea una carpeta data/ junto a tu archivo Python (por ejemplo, main.py) y coloca tasks.txt dentro antes de ejecutar. La sintaxis de la ruta ("data/tasks.txt" con /) es idéntica al Python real.

Pulsa el botón 📂 Files en la parte superior de la consola derecha y verás los dos archivos preparados data/tasks.txt (4 tareas) y data/log.txt (3 líneas de historial).

① Usa with open("data/tasks.txt", "r") as f: para abrir el archivo en modo lectura.

② Lee todo con f.read() y guárdalo en content.

③ Imprímelo con print(content).

(Si tu código se ejecuta correctamente, aparecerá la explicación.)

Editor Python

Ejecutar el código para ver el resultado

Cuando el archivo es un registro por línea (CSV sin cabecera, una lista separada por saltos de línea, líneas de log), f.readlines() es conveniente. Devuelve una lista de cadenas, una por línea, y cada elemento conserva el \n final.

Imprimirla directamente produce doble interlineado, así que el patrón estándar es aplicar .rstrip("\n") para quitar el salto final.

Usa data/log.txt (3 líneas de historial). Léelo como una lista con readlines() e imprime cada línea numerada. Este es el patrón típico para vistas de log y formato de informes de operaciones.

① Abre con with open("data/log.txt", "r") as f: y guarda f.readlines() en lines.

② Recorre con enumerate(lines, start=1) para empezar la numeración desde 1.

③ Quita el salto final con .rstrip() e imprime como f"{n}: {body}".

Editor Python

Ejecutar el código para ver el resultado

¿Archivos grandes? Lee línea a línea — readline y la morsa

f.read() y f.readlines() cargan el archivo entero en memoria. Eso está bien para archivos del tamaño de una configuración, pero un log de servidor de varios GB puede romper el programa al quedarse sin memoria.

f.readline() carga solo una línea cada vez, así que el uso de memoria se queda en lo que ocupa una línea. Cuando readline() alcanza el fin de archivo, devuelve la cadena vacía "", que usas como condición de salida del bucle.

readline() lee una línea cada vez
archivo(varios GB)readline()-> línea 1memoria:línea 1(continúa)readline()-> línea 2memoria:línea 2EOF alcanzadoreadline()-> ""el bucletermina
Lee una línea, procésala, sobrescribe con la siguiente — el archivo completo nunca vive en memoria. Incluso un archivo de varios GB usa solo «el tamaño de la línea más larga» de memoria. EOF devuelve "" para indicar al bucle que pare.
# Estilo clásico: sale al recibir cadena vacía
with open("data/log.txt", "r") as f:
    while True:
        line = f.readline()
        if not line:           # cadena vacía = EOF
            break
        print(line.rstrip())

El operador morsa := escribe lo mismo en una línea menos

Python 3.8 introdujo el operador morsa (:=), que te permite asignar y comprobar dentro de una expresión. Escribir while line := f.readline(): significa «pon el resultado de readline() en line y sigue iterando mientras no esté vacío» — todo el bucle en una línea.

Ahora lee data/tasks.txt con readline() + el operador morsa, una línea cada vez. El uso real son logs gigantes; usamos el archivo pequeño de tareas solo para ver la mecánica.

① Abre with open("data/tasks.txt", "r") as f:.

② Recorre con while line := f.readline(): para que cada línea vaya a line.

③ Quita el salto final con .rstrip() e imprime: print(line.rstrip()).

Editor Python

Ejecutar el código para ver el resultado

Escritura — modo w y modo a

Escribir es solo open() con otro segundo argumento. Dos modos cargan el peso práctico.

- "w" (write) — crear nuevo o sobrescribir. El contenido existente queda destruido.

- "a" (append) — añadir al final. El contenido existente se mantiene.

También existen dos métodos de escritura. f.write(s) escribe la cadena s directamente; f.writelines(lst) escribe una lista de cadenas de una sola vez. Si la ruta incluye una carpeta, el archivo se crea dentro (la carpeta debe existir ya).

w vs a
antes:ABCopen("w")f.write("XYZ")después:XYZantes:ABCopen("a")f.write("XYZ")después:ABCXYZsobrescribeañade
w borra el contenido existente en el momento que abres. a añade desde el final. Elegir el equivocado puede borrar un log importante — sé deliberado.
# modo w: escribe cadenas una a una
with open("data/done.txt", "w") as f:
    f.write("Escribir el informe\n")
    f.write("Responder correos\n")

# modo w: escribe una lista de golpe con writelines
with open("data/done.txt", "w") as f:
    f.writelines(["Escribir el informe\n", "Responder correos\n", "Asistir a la reunión\n"])

# modo a: añade al final
with open("data/done.txt", "a") as f:
    f.write("Hacer las compras\n")

Los saltos de línea \n no se añaden automáticamente

A diferencia de print(), ni f.write() ni f.writelines() añaden saltos de línea por ti. Llamar f.write("Hola") dos veces deja HolaHola en el archivo. Inserta \n explícitos dondequiera que realmente quieras un salto de línea.

Crea un nuevo done.txt (un registro de tareas hechas) dentro de la carpeta data/, escribe en él y vuelve a leerlo. La carpeta data/ ya existe, así que úsala directamente en la ruta.

① Abre con with open("data/done.txt", "w") as f:.

② Tras f.write("Tareas hechas:\n"), escribe f.write("Escribir el informe\n") y luego f.write("Responder correos\n") — tres escrituras en total.

③ Abre de nuevo con un with open("data/done.txt", "r") as f: aparte y print(f.read()) para mostrar todo el contenido.

④ Tras ejecutar, pulsa el botón 📂 Files de la cabecera — verás data/done.txt listado en el panel.

Editor Python

Ejecutar el código para ver el resultado

Reproduce el estado de data/done.txt del ejercicio anterior y luego añade un nuevo elemento al final. Vive la diferencia entre w y a en un solo script.

① Empieza con with open("data/done.txt", "w") as f: y f.write("Tareas hechas:\nEscribir el informe\n") para fijar el contenido inicial (esto resetea el archivo en cada ejecución).

② Luego con with open("data/done.txt", "a") as f:, añade f.write("Responder correos\n").

③ Por último, abre de nuevo con "r" y print(f.read()) para verificar.

Editor Python

Ejecutar el código para ver el resultado

Yendo más allá — Analiza un archivo y guarda el resultado en otro

Uno de los patrones más comunes en el trabajo real es leer un archivo de entrada, hacer algún análisis y escribir el resultado en otro archivo aparte. Solo usa open() dos veces — una con "r", otra con "w". El estilo más limpio es poner entrada → proceso → salida en tres bloques with separados.

# Analiza data/log.txt y guarda el resultado en data/log_summary.txt

# (1) Entrada: lee el log como una lista de líneas
with open("data/log.txt", "r") as src:
    lines = src.readlines()

# (2) Proceso: cuenta líneas, captura primera/última entrada
total   = len(lines)
first   = lines[0].rstrip()
last    = lines[-1].rstrip()
summary = f"count: {total}\nfirst: {first}\nlast: {last}\n"

# (3) Salida: escribe en otro archivo distinto
with open("data/log_summary.txt", "w") as dst:
    dst.write(summary)

print("Saved analysis to data/log_summary.txt")

data/products.txt contiene 4 líneas con la forma «nombre,precio». Léelo, calcula el total y escribe el resultado en un archivo aparte data/total.txt.

① Abre con with open("data/products.txt", "r") as f: y obtén la lista con f.readlines().

② Para cada línea, quita el salto final con .rstrip() y divide por "," para obtener nombre y precio. El precio es una cadena, así que conviértelo con int() antes de sumar.

③ Abre with open("data/total.txt", "w") as f: y escribe el resultado con f.write(f"total: {total}\n").

④ Verifica abriendo con "r" y print(f.read()).

Editor Python

Ejecutar el código para ver el resultado

encoding="utf-8" es el estándar para codificación de texto

En Python real, sueles escribir open(path, "r", encoding="utf-8") para especificar la codificación explícitamente. Intentar leer un archivo Shift-JIS como UTF-8 lanza UnicodeDecodeError, y al revés produce mojibake silencioso. El estándar mundial es UTF-8 — escribe los archivos nuevos en UTF-8 por defecto. El entorno del navegador codifica internamente UTF-8 por lo que omitir encoding= funciona aquí, pero hazlo costumbre cuando escribas scripts locales.

QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Qué significa el segundo argumento "r" en with open("data/notes.txt", "r") as f:?

Pregunta 2Cuando llamas a f.readline() repetidamente y el archivo termina, ¿qué valor vuelve?

Pregunta 3Si data/done.txt ya tiene contenido y abres con with open("data/done.txt", "w") as f:, ¿qué pasa con el contenido existente?