Leer y escribir ficheros en Python: open(), modos, encoding y gestión con with

Leer y escribir ficheros es una de las operaciones más básicas de cualquier programa, pero Python tiene varios detalles que hay que conocer para no cometer los errores más habituales: olvidar cerrar el fichero, no especificar el encoding o elegir el modo incorrecto.

open() y el bloque with

Siempre usa with para abrir ficheros: garantiza el cierre aunque ocurra una excepción.

# BIEN: con bloque with
with open("datos.txt", "r", encoding="utf-8") as f:
    contenido = f.read()
print(contenido)
# el fichero se cierra automáticamente al salir del with

# MAL: sin with — el fichero podría quedarse abierto si hay excepción
f = open("datos.txt", "r")
contenido = f.read()
f.close()

Modos de apertura

# 'r'  — lectura (por defecto). Falla si el fichero no existe.
# 'w'  — escritura. Crea el fichero o lo trunca si ya existe.
# 'a'  — append. Crea el fichero o añade al final si ya existe.
# 'x'  — creación exclusiva. Falla si el fichero ya existe.
# 'rb' — lectura binaria. Para imágenes, PDFs, etc.
# 'wb' — escritura binaria.

with open("log.txt", "a", encoding="utf-8") as f:
    f.write("nueva entrada de logn")

Métodos de lectura

# read(): todo el fichero como una cadena
with open("fichero.txt", encoding="utf-8") as f:
    todo = f.read()

# readlines(): lista de líneas (incluye n)
with open("fichero.txt", encoding="utf-8") as f:
    lineas = f.readlines()

# Iterar línea a línea (más eficiente en memoria)
with open("fichero.txt", encoding="utf-8") as f:
    for linea in f:
        print(linea.rstrip("n"))

# readline(): una línea cada vez
with open("fichero.txt", encoding="utf-8") as f:
    primera = f.readline()
    segunda = f.readline()

Ejemplo real: procesar un log de Nginx

from collections import Counter

def analizar_log(ruta_log):
    """Cuenta las IPs que más peticiones hacen en un log de acceso."""
    ips = Counter()
    with open(ruta_log, encoding="utf-8") as f:
        for linea in f:
            if linea.strip():
                ip = linea.split()[0]
                ips[ip] += 1
    return ips.most_common(10)

# top_ips = analizar_log("/var/log/nginx/access.log")

pathlib.Path: la forma moderna

from pathlib import Path

ruta = Path("datos") / "usuarios.txt"

# read_text y write_text simplifican el open() para texto
contenido = ruta.read_text(encoding="utf-8")
ruta.write_text("nuevo contenidon", encoding="utf-8")

# Append con open()
with ruta.open("a", encoding="utf-8") as f:
    f.write("línea adicionaln")

# Comprobar existencia, extensión, nombre
print(ruta.exists())    # True/False
print(ruta.suffix)      # '.txt'
print(ruta.stem)        # 'usuarios'
print(ruta.parent)      # PosixPath('datos')

# Iterar ficheros de un directorio
for fichero in Path(".").glob("*.py"):
    print(fichero.name)

Encoding: siempre explícito

# MAL: depende del encoding del sistema (distinto en Windows y Linux)
with open("fichero.txt") as f:
    datos = f.read()

# BIEN: encoding siempre explícito
with open("fichero.txt", encoding="utf-8") as f:
    datos = f.read()

# Para UTF-8 con BOM (común en ficheros de Windows)
with open("fichero.txt", encoding="utf-8-sig") as f:
    datos = f.read()

La regla: siempre with, siempre encoding="utf-8" salvo razón explícita para usar otro. Para rutas de fichero en código nuevo, usa pathlib.Path en lugar de cadenas de texto.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP