Menu

Manejo de archivos en Python: leer, escribir y añadir con seguridad

Cómo leer y escribir archivos en Python — la sentencia with, texto vs binario y la API moderna y más segura basada en paths.

Los archivos son solo strings con una ruta

La mayoría de programas eventualmente necesitan leer o escribir un archivo — configuraciones, datos de usuario, logs, exportaciones CSV, cachés pequeños. Python mantiene esto simple con una sola función incorporada, open(), más un bloque with para asegurar que las cosas se cierren limpiamente.

Vamos a repasar los casos comunes.

Leer un archivo entero

La lectura más simple:

with open("notes.txt") as f:
    contents = f.read()

print(contents)

open("notes.txt") abre el archivo para leer (el valor por defecto). El bloque with significa que Python cerrará el archivo cuando salgas del bloque — incluso si se lanza una excepción. Una vez cerrado, no puedes usar f; el texto vive en contents.

contents es un único string que contiene el archivo entero. Bien para archivos pequeños; mal para un log de 2 GB.

Leer línea a línea

Para archivos más grandes, itera en vez de leer todo en memoria:

with open("big.log") as f:
    for line in f:
        if "ERROR" in line:
            print(line.strip())

Cada iteración produce una línea incluyendo el salto de línea final — por eso .strip() aparece tanto. Si quieres una lista de líneas, f.readlines() hace eso, pero normalmente la iteración directa es lo que quieres.

Escribir un archivo

Para escribir, pasa el modo como segundo argumento:

with open("output.txt", "w") as f:
    f.write("first line\n")
    f.write("second line\n")

Dos cosas a tener en cuenta:

  • "w" sobrescribe. Si output.txt ya existe, su contenido desaparece en el momento en que open se ejecuta.
  • Tienes que añadir los saltos de línea tú. f.write("hello") escribe exactamente esos cinco caracteres — sin salto de línea final.

Para añadir en vez de sobrescribir:

with open("output.txt", "a") as f:
    f.write("another line\n")

También puedes meter varias líneas de una vez con writelines:

lines = ["a\n", "b\n", "c\n"]
with open("letters.txt", "w") as f:
    f.writelines(lines)

Misma regla: tú pones los saltos de línea.

print tiene un argumento file, que es una forma fácil de escribir sin los saltos de línea manuales:

with open("log.txt", "w") as f:
    print("started", file=f)
    print("finished", file=f)

Cada print escribe sus argumentos más un salto de línea final. Para salida informal, esta suele ser la forma más agradable.

Modo texto vs binario

Por defecto, open está en modo texto. Python decodifica bytes a strings (usando UTF-8 por defecto en plataformas modernas) y maneja la traducción de saltos de línea.

Para imágenes, PDFs, archivos compilados o cualquier cosa que no sea texto, abre en modo binario añadiendo "b" al modo:

with open("image.png", "rb") as f:
    data = f.read()

print(len(data))  # número de bytes

with open("image_copy.png", "wb") as f:
    f.write(data)

En modo binario, obtienes objetos bytes en vez de str, y Python no toca los finales de línea.

Especificar encoding

Para archivos de texto, sé explícito sobre el encoding. UTF-8 es casi siempre correcto en 2026:

with open("notes.txt", encoding="utf-8") as f:
    contents = f.read()

Si estás tratando con archivos legacy de un entorno solo-Windows, también podrías ver cp1252 o latin-1. Adivinar mal te da caracteres corrompidos o un UnicodeDecodeError.

pathlib: la forma moderna de manejar paths

El módulo pathlib de la librería estándar te da una API más ergonómica que los strings crudos:

from pathlib import Path

path = Path("notes.txt")

# Lectura y escritura simples.
contents = path.read_text(encoding="utf-8")
path.write_text("new contents\n", encoding="utf-8")

# Construir paths sin preocuparte por / vs \.
data_dir = Path("data")
log_path = data_dir / "today.log"

print(log_path)
print(log_path.exists())
print(log_path.suffix)       # ".log"
print(log_path.stem)         # "today"
print(log_path.parent)       # "data"

Path.read_text() y write_text() son atajos para el patrón with open(...) as f cuando solo quieres lecturas y escrituras de una sola vez. Para iteración línea a línea, sigues usando open o path.open().

Un pequeño ejemplo de principio a fin

Leer una lista de elementos de un archivo, filtrarlos y escribir el resultado en otro archivo:

from pathlib import Path

source = Path("items.txt")
destination = Path("filtered.txt")

items = source.read_text().splitlines()
kept = [item for item in items if item and not item.startswith("#")]

destination.write_text("\n".join(kept) + "\n")

print(f"Kept {len(kept)} items out of {len(items)}")

splitlines() es el compañero orientado a líneas de join. Parte por caracteres de salto de línea sin mantenerlos — útil cuando vas a volver a juntar las piezas de todas formas.

Cuando las cosas van mal

Abrir un archivo que no existe lanza FileNotFoundError. Intentar leer un archivo para el que no tienes permiso lanza PermissionError. Ambos son subclases de OSError, que a su vez es subclase de Exception — hablaremos de manejar excepciones apropiadamente en la siguiente página.

Por ahora, un adelanto rápido de cómo se ve el manejo de errores:

from pathlib import Path

path = Path("maybe.txt")

try:
    contents = path.read_text()
except FileNotFoundError:
    print("File doesn't exist — starting fresh.")
    contents = ""

print(repr(contents))

Hábitos clave

  • Usa siempre with open(...) en vez de open crudo + cierre manual.
  • Pasa siempre encoding= para archivos de texto; UTF-8 por defecto.
  • Itera archivos grandes línea a línea; no los leas enteros con .read().
  • Para paths y patrones comunes de lectura/escritura, usa pathlib — te ahorrará mucha gimnasia con strings.

A continuación: JSON. La mayoría de archivos de texto del mundo real que leas no son líneas planas — están estructurados, y JSON es la forma más común. Los mismos hábitos de with open(...) se trasladan directamente.

Preguntas frecuentes

¿Cómo leo un archivo en Python?

Usa open() con la sentencia with, que cierra el archivo automáticamente cuando termines. with open('file.txt') as f: contents = f.read() lee el archivo entero en un string. Para línea a línea, itera directamente sobre el objeto archivo: for line in f:.

¿Cuál es la diferencia entre los modos 'r', 'w' y 'a'?

'r' es read (el valor por defecto). 'w' es write — crea el archivo o lo trunca si existe. 'a' es append — añade al final del archivo sin borrar lo que hay. Añade 'b' para modo binario o '+' para lectura+escritura.

¿Por qué usar with open en vez de open a secas?

La sentencia with garantiza que el archivo se cierra incluso si ocurre un error a mitad. Sin with, te toca llamar a .close() tú mismo y acordarte de hacerlo en los caminos de error. with es más seguro y menos código.

Aprende a programar con Coddy

COMENZAR