W3docs

Leer archivos en Python – Guía completa

Aprende todas las formas de leer archivos en Python: read(), readline(), readlines(), iteración de líneas, modo binario, codificación y pathlib.

Leer archivos es una de las tareas más comunes en Python, ya sea para cargar configuraciones, procesar registros, importar datos CSV o leer recursos binarios. Este capítulo cubre todos los métodos que Python ofrece para leer el contenido de archivos: desde la llamada más simple read() hasta la iteración línea por línea eficiente en memoria, el modo binario, el manejo de codificaciones, el control de la posición en el archivo y la API moderna pathlib.

Abrir un archivo para lectura

Toda operación con archivos comienza con la función incorporada open(). Para abrir un archivo en modo lectura, usa la cadena de modo "r" (que es el valor predeterminado cuando no se especifica ningún modo):

file_object = open("notes.txt", "r", encoding="utf-8")
  • "r" — abre para lectura; lanza FileNotFoundError si el archivo no existe.
  • encoding="utf-8" — especifica siempre la codificación de caracteres para archivos de texto, de modo que tu código funcione de manera idéntica en Windows, macOS y Linux.

Utiliza siempre un bloque with

La forma más segura de abrir un archivo es dentro de una sentencia with. Python cierra el archivo automáticamente cuando el bloque termina, incluso si ocurre una excepción, lo que evita fugas de recursos y garantiza que los datos en búfer se vacíen.

with open("notes.txt", "r", encoding="utf-8") as f:
    contents = f.read()
# File is automatically closed here

Llamar a open() fuera de un bloque with y olvidarse de file.close() es una fuente frecuente de errores de "demasiados archivos abiertos" en scripts de larga ejecución.

Leer el archivo completo con read()

read() devuelve el contenido completo del archivo como una sola cadena.

Leer un archivo completo de una vez

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

print(contents)

Usa read() cuando:

  • El archivo es lo suficientemente pequeño como para caber cómodamente en memoria.
  • Necesitas el texto completo como una sola cadena (por ejemplo, para analizar o buscar).

Para archivos que podrían ser grandes (registros, volcados de datos), prefiere los enfoques línea por línea que se describen a continuación.

Leer un número fijo de caracteres

Pasa un entero n a read(n) para leer como máximo n caracteres desde la posición actual. Las llamadas posteriores a read(n) continúan desde donde terminó la última lectura.

Leer los primeros 50 caracteres

with open("notes.txt", "r", encoding="utf-8") as f:
    first_chunk = f.read(50)
    second_chunk = f.read(50)

print(repr(first_chunk))
print(repr(second_chunk))

Este enfoque por fragmentos es útil cuando quieres previsualizar un archivo o procesarlo en piezas de tamaño fijo sin cargar todo en memoria.

Leer una línea a la vez con readline()

readline() lee una línea del archivo, incluido el carácter de nueva línea \n al final. Devuelve una cadena vacía "" cuando se alcanza el final del archivo, lo que facilita iterar hasta EOF.

Leer un archivo línea por línea con readline()

with open("notes.txt", "r", encoding="utf-8") as f:
    line = f.readline()
    while line:
        print(line, end="")   # line already contains '\n'
        line = f.readline()

El argumento end="" en print() evita que aparezca una doble nueva línea (una de la línea del archivo y otra del valor predeterminado de print).

readline() es útil cuando necesitas procesar una línea de encabezado de forma diferente al resto, o cuando quieres dejar de leer a mitad del archivo según una condición.

Iterar sobre las líneas (la forma más Pythónica)

Iterar directamente sobre un objeto de archivo es la forma más idiomática y eficiente en memoria de procesar un archivo de texto línea por línea. Python lee una línea a la vez sin cargar el archivo completo en memoria.

Iterar sobre las líneas con un bucle for

with open("notes.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line, end="")

Este patrón es preferible a read() + split("\n") y a llamar a readline() en un bucle while, ya que es más corto y maneja correctamente todos los casos especiales (incluidos los archivos que no terminan con una nueva línea).

Buscar un patrón mientras se itera

with open("server.log", "r", encoding="utf-8") as f:
    for line in f:
        if "ERROR" in line:
            print(line, end="")

Leer todas las líneas en una lista con readlines()

readlines() devuelve una lista donde cada elemento es una línea del archivo (con el carácter de nueva línea incluido). Esto carga el archivo completo en memoria.

Leer todas las líneas en una lista

with open("notes.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()

print(lines[0])        # first line
print(lines[-1])       # last line
print(len(lines))      # total number of lines

Usa readlines() cuando necesites acceso aleatorio a líneas específicas por índice. Para el procesamiento secuencial de arriba a abajo, el patrón for line in f es más eficiente en memoria.

Eliminar los caracteres de nueva línea

Las líneas devueltas por readline(), readlines() y la iteración con el bucle for incluyen el \n al final. Usa .strip() o .rstrip("\n") para eliminarlo:

with open("notes.txt", "r", encoding="utf-8") as f:
    lines = [line.rstrip("\n") for line in f]

print(lines)  # ['Line one', 'Line two', 'Line three']

Elegir el método de lectura adecuado

MétodoDevuelve¿Carga el archivo completo?Ideal para
f.read()strArchivos pequeños, análisis de texto completo
f.read(n)strNo (por fragmentos)Transmisión de tamaño fijo
f.readline()strNoParadas condicionales línea por línea
for line in fstr (uno por iteración)NoProcesamiento secuencial de líneas
f.readlines()list[str]Acceso aleatorio por índice a las líneas

Posición en el archivo: tell() y seek()

Todo objeto de archivo abierto mantiene un puntero de posición interno que avanza conforme lees. Dos métodos te permiten inspeccionarlo y controlarlo:

  • tell() — devuelve el desplazamiento en bytes desde el inicio del archivo.
  • seek(offset, whence=0) — mueve el puntero. Con whence=0 (predeterminado), el desplazamiento es desde el inicio; whence=1 es desde la posición actual; whence=2 es desde el final.

Leer un archivo dos veces usando seek(0)

with open("notes.txt", "r", encoding="utf-8") as f:
    first_pass = f.read()
    print(f"Position after first read: {f.tell()}")

    f.seek(0)   # rewind to the beginning
    second_pass = f.read()

print(first_pass == second_pass)  # True

seek() es especialmente útil en el modo "r+" (lectura y escritura), donde podrías leer una sección del archivo y luego sobrescribir una parte específica en la misma llamada a open().

Manejo de errores al leer

Un script bien escrito siempre anticipa las formas en que puede fallar la lectura de un archivo.

Manejar errores comunes de lectura

try:
    with open("data.txt", "r", encoding="utf-8") as f:
        content = f.read()
except FileNotFoundError:
    print("Error: the file does not exist.")
except PermissionError:
    print("Error: you do not have permission to read this file.")
except UnicodeDecodeError:
    print("Error: the file contains bytes that are not valid UTF-8.")
except OSError as e:
    print(f"OS error: {e}")

Excepciones comunes que encontrarás:

ExcepciónCuándo ocurre
FileNotFoundErrorLa ruta no apunta a un archivo existente
PermissionErrorEl proceso no tiene permiso de lectura
IsADirectoryErrorLa ruta apunta a un directorio, no a un archivo
UnicodeDecodeErrorLos bytes del archivo no coinciden con la codificación especificada

Consulta Python Try Except para obtener una guía completa sobre el manejo de excepciones.

Codificación de caracteres

Cuando Python abre un archivo en modo texto, debe saber cómo convertir los bytes en bruto en caracteres. Pasa siempre encoding= de forma explícita en lugar de depender del valor predeterminado de la plataforma, que difiere entre Windows (cp1252) y la mayoría de los sistemas Unix (utf-8).

Valores de codificación comunes:

CodificaciónUsar cuando
"utf-8"Archivos modernos, contenido web, la mayoría de proyectos Python
"utf-8-sig"Archivos UTF-8 creados por herramientas de Windows que anteponen un BOM
"latin-1"Archivos heredados de Europa Occidental
"cp1252"Archivos de texto ANSI de Windows

Detectar o ignorar problemas de codificación:

Si no estás seguro de la codificación de un archivo, puedes indicarle a Python que reemplace los bytes no decodificables con un marcador de posición en lugar de lanzar un error:

with open("mystery.txt", "r", encoding="utf-8", errors="replace") as f:
    content = f.read()

Otros valores para errors incluyen "ignore" (omitir silenciosamente los bytes incorrectos) y "strict" (predeterminado: lanza UnicodeDecodeError).

Leer archivos binarios

Abre un archivo en modo binario añadiendo "b" a la cadena de modo ("rb"). El modo binario devuelve objetos bytes en bruto en lugar de cadenas, lo cual es correcto para imágenes, audio, archivos comprimidos, ejecutables y cualquier dato que no sea texto.

Leer un archivo binario

with open("photo.jpg", "rb") as f:
    data = f.read()

print(type(data))   # <class 'bytes'>
print(len(data))    # size in bytes

Copiar un archivo binario

with open("photo.jpg", "rb") as src:
    data = src.read()

with open("photo_backup.jpg", "wb") as dst:
    dst.write(data)

No especifiques encoding en modo binario: Python lanza ValueError si lo intentas.

Leer archivos grandes de forma eficiente

Cargar un archivo de varios gigabytes con read() puede agotar la memoria del sistema. Las soluciones son:

Iteración línea por línea (archivos de texto)

with open("huge_log.txt", "r", encoding="utf-8") as f:
    for line in f:
        process(line)   # only one line in memory at a time

Fragmentos de tamaño fijo (archivos binarios)

CHUNK_SIZE = 65536  # 64 KB

with open("large_file.bin", "rb") as f:
    while True:
        chunk = f.read(CHUNK_SIZE)
        if not chunk:
            break
        process(chunk)

Ambos patrones mantienen el uso de memoria constante independientemente del tamaño del archivo.

Leer archivos con pathlib

Python 3.4 introdujo pathlib.Path, que proporciona una interfaz orientada a objetos para las rutas del sistema de archivos. Para lecturas y escrituras simples de una sola vez, los objetos Path son más concisos que open().

Leer texto con Path.read_text()

from pathlib import Path

content = Path("notes.txt").read_text(encoding="utf-8")
print(content)

Leer bytes con Path.read_bytes()

from pathlib import Path

data = Path("photo.jpg").read_bytes()
print(len(data))  # file size in bytes

read_text() y read_bytes() abren el archivo, leen su contenido completo y lo cierran en una sola llamada. Úsalos para archivos pequeños cuando solo necesitas el contenido. Usa open() con un bloque with cuando necesites iteración línea por línea, lectura por fragmentos, seek() o cualquier otro control detallado.

Verificar que un archivo existe antes de leerlo

from pathlib import Path

p = Path("data.txt")
if p.exists() and p.is_file():
    content = p.read_text(encoding="utf-8")
else:
    print("File not found.")

Nota: p.exists() puede devolver un resultado obsoleto en código multihilo. En esos casos es más seguro intentar la lectura y capturar FileNotFoundError.

Ejemplo práctico: leer un archivo de configuración simple

Muchos scripts leen un archivo de configuración en texto plano que almacena un par clave=valor por línea. Aquí tienes un ejemplo completo y funcional:

Analizar un archivo de configuración clave=valor

from pathlib import Path

def load_config(path):
    config = {}
    with open(path, "r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith("#"):
                continue          # skip blank lines and comments
            key, _, value = line.partition("=")
            config[key.strip()] = value.strip()
    return config

# Example config.txt contents:
# host = localhost
# port = 8080
# debug = true

config = load_config("config.txt")
# config == {'host': 'localhost', 'port': '8080', 'debug': 'true'}

str.partition("=") divide solo en el primer =, por lo que los valores que contienen = (como las cadenas en Base64) se manejan correctamente.

Capítulos relacionados

Was this page helpful?