Saltar a contenido

OPERACIONES SOBRE FICHEROS

Apertura y cierre de ficheros

La función open()

La función open() es el punto de entrada para trabajar con cualquier fichero en Python. Devuelve un objeto fichero con métodos para leer o escribir datos.

Su sintaxis básica es:

open(ruta, mode="r", encoding=None)

Los parámetros más importantes son:

  • ruta: cadena o Path con la ubicación del fichero
  • mode: modo de apertura (lectura, escritura, etc.) — por defecto "r"
  • encoding: codificación de caracteres — se recomienda siempre indicarlo explícitamente

Modos de apertura

El parámetro mode controla qué operaciones se pueden realizar sobre el fichero y qué ocurre si este ya existe o no existe.

Modo Significado ¿Crea el fichero? ¿Borra contenido?
"r" Lectura (por defecto) No No
"w" Escritura
"a" Añadir al final (append) No
"x" Creación exclusiva (error si ya existe)
"r+" Lectura y escritura No No
"b" Modo binario (se combina con los anteriores: "rb", "wb")
"t" Modo texto (por defecto, se puede omitir)

Combinación de modos

Los modos se pueden combinar: "rb" abre en modo lectura binaria, "w+" permite leer y escribir borrando el contenido previo.

Cierre explícito con close()

Tras usar un fichero es obligatorio cerrarlo para liberar el recurso del sistema operativo y asegurar que los datos se escriben en disco.

1
2
3
4
5
fichero = open("notas.txt", "r", encoding="utf-8")
contenido = fichero.read()
print(contenido)

fichero.close()  ## Es obligatorio cerrar el fichero

El problema del cierre manual es que si ocurre una excepción entre la apertura y el close(), el fichero nunca se cierra:

1
2
3
4
fichero = open("notas.txt", "r", encoding="utf-8")
contenido = fichero.read()
procesar(contenido)   ## si esta línea lanza una excepción...
fichero.close()       ## ...esta línea nunca se ejecuta

El gestor de contexto with

Python proporciona el gestor de contexto with para garantizar que el fichero se cierre siempre, incluso si se produce un error:

1
2
3
4
with open("notas.txt", "r", encoding="utf-8") as fichero:
    contenido = fichero.read()
    print(contenido)
## Al salir del bloque with, el fichero se cierra automáticamente

El bloque with gestiona el ciclo de vida del fichero:

  1. Abre el fichero y lo asigna a la variable indicada tras as
  2. Ejecuta el bloque indentado
  3. Cierra el fichero siempre al salir del bloque, haya error o no

Usa siempre with para abrir ficheros. Es la forma recomendada en Python y evita errores difíciles de depurar relacionados con ficheros no cerrados.

Abrir varios ficheros a la vez

Se pueden abrir múltiples ficheros en un mismo with:

1
2
3
with open("entrada.txt", "r", encoding="utf-8") as origen, \
     open("salida.txt", "w", encoding="utf-8") as destino:
    destino.write(origen.read())

Codificación de caracteres

La codificación (encoding) determina cómo se convierten los caracteres a bytes y viceversa.

Si no se especifica, Python usa la codificación del sistema operativo, que varía entre plataformas. Esto provoca errores difíciles de reproducir, especialmente con caracteres especiales del español (tildes, ñ).

1
2
3
## Siempre indicar encoding explícitamente
with open("alumnos.txt", "r", encoding="utf-8") as f:
    datos = f.read()

Usa siempre encoding=\"utf-8\"

UTF-8 es el estándar de facto en aplicaciones modernas. Soporta todos los caracteres del español y de prácticamente cualquier idioma. Si abres un fichero sin indicar encoding y el sistema del alumno o del servidor tiene otra configuración, obtendrás errores de codificación.

Antipatrón: abrir ficheros sin encoding ni with

## Incorrecto: sin encoding ni gestor de contexto
f = open("notas.txt")
datos = f.read()
## Correcto
with open("notas.txt", "r", encoding="utf-8") as f:
    datos = f.read()

Lectura de ficheros de texto

Para los ejemplos de esta sección usaremos el fichero notas.txt con el siguiente contenido:

Ana García: 8.5
Carlos López: 6.0
María Fernández: 9.2
Pedro Martín: 5.5

El método read()

read() lee todo el contenido del fichero de una vez y lo devuelve como una única cadena de texto.

1
2
3
4
with open("notas.txt", "r", encoding="utf-8") as f:
    contenido = f.read()

print(contenido)
Ana García: 8.5
Carlos López: 6.0
María Fernández: 9.2
Pedro Martín: 5.5

El texto devuelto por read() incluye los saltos de línea \n. Si el fichero tiene 4 líneas, el string contendrá 3 caracteres \n (uno al final de cada línea, excepto posiblemente la última).

Se puede leer solo una parte del fichero indicando el número de caracteres:

1
2
3
with open("notas.txt", "r", encoding="utf-8") as f:
    primeros = f.read(10)   ## Lee los primeros 10 caracteres
print(primeros)
Ana García

El método readline()

readline() lee una sola línea cada vez que se llama, devolviendo la cadena incluyendo el \n del final.

Es útil cuando el fichero es muy grande y no interesa cargarlo entero en memoria:

1
2
3
4
5
6
with open("notas.txt", "r", encoding="utf-8") as f:
    linea1 = f.readline()
    linea2 = f.readline()

print(linea1)   ## 'Ana García: 8.5\n'
print(linea2)   ## 'Carlos López: 6.0\n'

Cuando se llega al final del fichero, readline() devuelve una cadena vacía "".

Este comportamiento permite leer el fichero completo en un bucle:

1
2
3
4
5
6
with open("notas.txt", "r", encoding="utf-8") as f:
    while True:
        linea = f.readline()
        if not linea:       ## cadena vacía = fin de fichero
            break
        print(linea.strip())

El método readlines()

readlines() lee todas las líneas de una vez y las devuelve como una lista de cadenas. Cada elemento de la lista incluye el \n del final.

1
2
3
4
with open("notas.txt", "r", encoding="utf-8") as f:
    lineas = f.readlines()

print(lineas)
['Ana García: 8.5\n', 'Carlos López: 6.0\n', 'María Fernández: 9.2\n', 'Pedro Martín: 5.5\n']

Para trabajar con las líneas sin el \n se usa strip():

1
2
3
4
5
with open("notas.txt", "r", encoding="utf-8") as f:
    lineas = f.readlines()

for linea in lineas:
    print(linea.strip())

Iteración directa sobre el fichero

La forma más Pythónica y eficiente de leer un fichero línea a línea es iterar directamente sobre el objeto fichero. Python lo trata como un iterable de líneas:

1
2
3
with open("notas.txt", "r", encoding="utf-8") as f:
    for linea in f:
        print(linea.strip())
Ana García: 8.5
Carlos López: 6.0
María Fernández: 9.2
Pedro Martín: 5.5

Esta forma es la más recomendada para leer líneas: no carga todo el fichero en memoria y el código es muy legible.

Ejemplo: extraer nombres y notas

Usando la iteración directa, podemos procesar el fichero de notas para obtener la lista de alumnos:

alumnos = []

with open("notas.txt", "r", encoding="utf-8") as f:
    for linea in f:
        partes = linea.strip().split(": ")
        nombre = partes[0]
        nota = float(partes[1])
        alumnos.append({"nombre": nombre, "nota": nota})

for alumno in alumnos:
    print(f"{alumno['nombre']}{alumno['nota']}")
Ana García → 8.5
Carlos López → 6.0
María Fernández → 9.2
Pedro Martín → 5.5

Comparativa de métodos de lectura

Método Devuelve Cuándo usarlo
read() str con todo el contenido Ficheros pequeños, cuando necesitas todo el texto de una vez
readline() str con una línea Cuando procesas el fichero secuencialmente y puede ser muy grande
readlines() list de líneas Cuando necesitas acceder por índice a líneas concretas
Iteración directa Línea a línea (más eficiente) La opción recomendada para recorrer todas las líneas

Antipatrón: usar read() en ficheros grandes

## Incorrecto: carga el fichero entero en memoria
## Si el fichero tiene millones de líneas, esto puede agotar la RAM
with open("registro_enorme.log", "r", encoding="utf-8") as f:
    todas = f.read()
    for linea in todas.split("\n"):
        procesar(linea)
## Correcto: procesa línea a línea sin cargar todo en memoria
with open("registro_enorme.log", "r", encoding="utf-8") as f:
    for linea in f:
        procesar(linea.strip())

Escritura en ficheros de texto

El método write()

write() escribe una cadena de texto en el fichero y devuelve el número de caracteres escritos.

1
2
3
with open("notas.txt", "w", encoding="utf-8") as f:
    f.write("Ana García: 8.5\n")
    f.write("Carlos López: 6.0\n")

write() no añade el salto de línea automáticamente. Si quieres que cada llamada ocupe una línea distinta, debes añadir \n al final de cada cadena.

El resultado en el fichero notas.txt:

Ana García: 8.5
Carlos López: 6.0

El método writelines()

writelines() escribe una lista de cadenas en el fichero, una tras otra. Al igual que write(), no añade saltos de línea automáticamente.

alumnos = [
    "Ana García: 8.5",
    "Carlos López: 6.0",
    "María Fernández: 9.2",
]

lineas = [alumno + "\n" for alumno in alumnos]

with open("notas.txt", "w", encoding="utf-8") as f:
    f.writelines(lineas)

writelines() no añade saltos de línea entre elementos. Si los elementos de la lista no terminan en \n, todas las cadenas quedarán escritas seguidas en la misma línea.

Modo escritura "w" vs modo append "a"

La diferencia entre estos dos modos es fundamental:

Modo "w" — escritura

Abre el fichero para escribir. Si el fichero ya existe, borra todo su contenido antes de escribir. Si no existe, lo crea.

1
2
3
with open("notas.txt", "w", encoding="utf-8") as f:
    f.write("Registro nuevo\n")
## El contenido previo de notas.txt ha desaparecido

Modo "a" — append (añadir)

Abre el fichero para escribir al final del contenido existente. Si el fichero no existe, lo crea. Si existe, conserva lo que había.

1
2
3
with open("notas.txt", "a", encoding="utf-8") as f:
    f.write("Pedro Martín: 5.5\n")
## La nueva línea se añade al final, sin borrar lo anterior

Comparativa

Modo El fichero ya existe El fichero no existe
"w" Borra el contenido y escribe desde el principio Lo crea
"a" Escribe al final conservando el contenido Lo crea

Ejemplo: registro acumulativo de notas

Un caso de uso habitual de "a" es añadir registros a un fichero de log:

1
2
3
4
5
6
7
8
9
def registrar_nota(nombre, nota):
    """Añade una línea de nota al fichero, sin borrar las anteriores."""
    with open("notas.txt", "a", encoding="utf-8") as f:
        f.write(f"{nombre}: {nota}\n")


registrar_nota("Ana García", 8.5)
registrar_nota("Carlos López", 6.0)
registrar_nota("María Fernández", 9.2)

Cada vez que se ejecuta registrar_nota(), la línea se añade al final del fichero sin borrar las anteriores.

Uso de print() para escribir en ficheros

La función print() admite el parámetro file para redirigir la salida a un objeto fichero. Tiene la ventaja de añadir el salto de línea automáticamente:

1
2
3
with open("notas.txt", "w", encoding="utf-8") as f:
    for nombre, nota in [("Ana", 8.5), ("Carlos", 6.0)]:
        print(f"{nombre}: {nota}", file=f)

Antipatrón: usar modo \"w\" sin querer borrar el contenido

## Incorrecto: al abrir con "w", se borra el fichero existente
## Si el objetivo es añadir un registro, esto destruye los anteriores
with open("notas.txt", "w", encoding="utf-8") as f:
    f.write("Pedro Martín: 5.5\n")
## Correcto: usar "a" para añadir sin borrar
with open("notas.txt", "a", encoding="utf-8") as f:
    f.write("Pedro Martín: 5.5\n")

Antipatrón: olvidar el salto de línea en write()

## Incorrecto: todas las líneas quedan pegadas
with open("notas.txt", "w", encoding="utf-8") as f:
    f.write("Ana García: 8.5")
    f.write("Carlos López: 6.0")
## Resultado en el fichero: Ana García: 8.5Carlos López: 6.0
## Correcto: añadir \n al final de cada línea
with open("notas.txt", "w", encoding="utf-8") as f:
    f.write("Ana García: 8.5\n")
    f.write("Carlos López: 6.0\n")