Archivos de texto en Python — teoría con un diario de entrenamientos, modos que no perdonan y saltos de línea escondidos (y el ‘w’ que se comió mi diario)
A principios de octubre empecé a apuntar mis entrenos en un archivo de texto: una línea por sesión, con la fecha, el deporte y los minutos. Llevaba tres sesiones y quise añadir la cuarta con un programita de cinco líneas. Lo ejecuté, abrí el diario y… solo estaba la sesión de hoy. Las otras tres habían desaparecido. Este es el programa, casi tal cual:
# Quería apuntar el entreno de hoy en mi diario... y me lo cargué
f = open('diario.txt', 'w', encoding='utf-8') # así tenía el diario: tres sesiones
f.write('2026-10-05;carrera;35\n')
f.write('2026-10-06;bici;50\n')
f.write('2026-10-08;natación;40\n')
f.close()
def contar_sesiones(nombre):
f = open(nombre, 'r', encoding='utf-8')
n = 0
for linea in f: # una vuelta por línea del archivo
n += 1
f.close()
return n
print('Sesiones antes:', contar_sesiones('diario.txt'))
f = open('diario.txt', 'w', encoding='utf-8') # para "añadir" la de hoy... con 'w'
f.write('2026-10-09;carrera;30\n')
f.close()
print('Sesiones después:', contar_sesiones('diario.txt'))
Y esto es lo que sacó por pantalla:
Sesiones antes: 3 Sesiones después: 1
De 3 sesiones a 1. No hubo ningún error, ningún aviso, nada en rojo. El culpable es una sola letra: la 'w' del segundo open(). Abrir un archivo en modo escritura lo vacía en el mismo momento en que se abre, antes de escribir nada. Lo que yo quería era el modo 'a' (añadir). Hoy vamos a ver por qué pasa esto y todo lo demás que necesitas para leer y escribir archivos de texto sin sustos.
En este artículo aprendes qué es un archivo de texto, cómo se abre y se cierra, los modos 'r', 'w' y 'a', el esquema estándar de lectura con readline(), el recorrido con for, read(), las dos formas de escribir (print(..., file=f) y write()), la cláusula with, la codificación y el módulo os. Vienes de las expresiones regulares en Python, que te vendrán bien en los ejercicios, y cuando acabes tienes la práctica de archivos de texto. El ejemplo guía es mi diario de entrenamientos.
Tabla de Contenidos
¿Qué es un archivo de texto?
Un archivo de texto es una secuencia de caracteres guardada fuera del programa, en el disco. Entre esos caracteres están los finales de línea, el carácter '\n'. Por eso también se puede ver como una secuencia de líneas: cada línea es una tira de caracteres que termina en '\n'. Los .txt, los .csv, los .html y tus propios .py son archivos de texto.
Este es mi diario, el archivo entrenos.txt que usaremos durante toda la teoría:
# diario de entrenamientos: fecha;deporte;minutos 2026-10-05;carrera;35 2026-10-06;bici;50 2026-10-08;natación;40 2026-10-09; carrera ;30 2026-10-11;yoga;veinte 2026-10-12;fútbol;90 2026-10-14;bici;45
Fíjate en que no es perfecto, y eso es a propósito: tiene un comentario arriba, una línea vacía (la cuarta), una línea con espacios de más alrededor de carrera (y, aunque aquí no se vea, dos espacios y un tabulador al final), y una sesión de yoga con veinte escrito en letras. Los archivos de verdad son así.
Un archivo vive fuera de tu programa. Lo crean, cambian y borran los programas, pero lo gestiona el sistema de gestión de archivos del sistema operativo. Por eso hablar con un archivo tiene tres etapas: abrir (conectar el programa con el archivo), transferir (leer o escribir) y cerrar (soltar la conexión y terminar las escrituras pendientes).
Abrir y cerrar un archivo
Se abre con la función open(), que recibe el nombre del archivo y devuelve un manejador: un objeto que representa la conexión. A partir de ahí trabajas con el manejador (f), no con el nombre.
# Las tres etapas: abrir, transferir y cerrar
f = open('entrenos.txt', 'r', encoding='utf-8') # 1. abrir: f es el manejador del archivo
primera = f.readline() # 2. transferir: lee hasta el primer '\n', incluido
f.close() # 3. cerrar: libera el archivo
print(primera, end='') # la línea ya trae su '\n'
print(repr(primera)) # repr() enseña el '\n' que print() esconde
print(f.closed) # True: el manejador ya está cerrado
Al ejecutarlo:
# diario de entrenamientos: fecha;deporte;minutos '# diario de entrenamientos: fecha;deporte;minutos\n' True
Vamos por partes:
open('entrenos.txt', 'r', encoding='utf-8'): el primer argumento es el nombre; si solo pones el nombre «corto», Python lo busca en la carpeta de trabajo (desde donde se ejecuta el programa). El segundo,'r', es el modo lectura (es el modo por omisión, así queopen('entrenos.txt')haría lo mismo). El tercero,encoding, dice cómo están codificados los caracteres; lo vemos más abajo.f.readline()lee una línea: desde donde se quedó hasta el siguiente'\n', incluido.f.close()cierra. Después,f.closedvaleTrue.- La primera línea sale dos veces: con
print(primera, end='')se ve como en el archivo; conrepr(primera)se ve lo que hay de verdad, con el'\n'del final a la vista.
FileNotFoundError: abrir para leer algo que no existe
El modo 'r' exige que el archivo exista. Si te equivocas en el nombre (o estás en otra carpeta), revienta:
# 'r' exige que el archivo exista (el mío se llama entrenos.txt)
f = open('entrenamientos.txt', 'r', encoding='utf-8')
El mensaje es muy claro:
Traceback (most recent call last):
File "no_existe.py", line 2, in <module>
f = open('entrenamientos.txt', 'r', encoding='utf-8')
FileNotFoundError: [Errno 2] No such file or directory: 'entrenamientos.txt'
Ejecutar el programa desde otra carpeta. Si en VS Code o en la terminal la carpeta de trabajo no es la del archivo, open('entrenos.txt') no lo encuentra aunque «esté ahí al lado». Comprueba la ruta o usa os.path.exists() antes de abrir (lo ves al final).
Los modos ‘r’, ‘w’ y ‘a’
Los tres modos que vas a usar con archivos de texto:
| Modo | Para qué | Si el archivo no existe | Si ya existe |
|---|---|---|---|
'r' | leer | FileNotFoundError | lo lee desde el principio |
'w' | escribir | lo crea vacío | lo vacía al abrir |
'a' | añadir | lo crea vacío | escribe al final, sin borrar |
Míralos en acción sobre el mismo archivo, semana.txt:
# Los tres modos sobre el mismo archivo
def mostrar(nombre):
f = open(nombre, 'r', encoding='utf-8')
print(repr(f.read())) # el archivo entero en una string, con los '\n' a la vista
f.close()
f = open('semana.txt', 'w', encoding='utf-8') # no existe: 'w' lo crea vacío
f.write('lunes;carrera;35\n')
f.close()
mostrar('semana.txt')
f = open('semana.txt', 'a', encoding='utf-8') # 'a': el cursor empieza al final, no borra nada
f.write('martes;bici;50\n')
f.close()
mostrar('semana.txt')
f = open('semana.txt', 'w', encoding='utf-8') # 'w' otra vez: vacía el archivo antes de escribir
f.write('miércoles;yoga;20\n')
f.close()
mostrar('semana.txt')
La función mostrar() lee el archivo entero con read() (lo vemos enseguida) y lo enseña con repr(). Esta es la salida, una línea por cada vez que se llama:
'lunes;carrera;35\n' 'lunes;carrera;35\nmartes;bici;50\n' 'miércoles;yoga;20\n'
- El primer
'w'creasemana.txt(no existía) y escribe el lunes. - El
'a'coloca el cursor al final y escribe el martes detrás: ahora hay dos líneas. - El segundo
'w'vacía el archivo al abrirlo y escribe el miércoles. El lunes y el martes ya no están.
Esto es exactamente lo que me pasó en el gancho, y el dibujo lo resume:
Antes de escribir open(..., 'w'), pregúntate: «¿me da igual perder lo que haya en este archivo?». Si la respuesta es no, quieres 'a'. El 'w' es para archivos que se rehacen enteros cada vez, como un informe.
El esquema estándar de lectura con readline()
readline() lee una línea cada vez que la llamas. Cuando ya no quedan líneas, devuelve la string vacía ''. Con eso se monta el esquema clásico de recorrido «hasta que se cumpla una condición»:
# Esquema estándar de lectura: readline() hasta que devuelve ''
def mostrar(nombre):
f = open(nombre, 'r', encoding='utf-8')
linea = f.readline() # intento leer la primera línea
while linea != '': # '' solo llega al final; una línea vacía del archivo es '\n'
print(linea, end='') # la línea ya trae su '\n': end='' evita una línea en blanco extra
linea = f.readline() # la siguiente (o '' si se acabó)
f.close()
mostrar('entrenos.txt')
La salida reproduce el archivo tal cual:
# diario de entrenamientos: fecha;deporte;minutos 2026-10-05;carrera;35 2026-10-06;bici;50 2026-10-08;natación;40 2026-10-09; carrera ;30 2026-10-11;yoga;veinte 2026-10-12;fútbol;90 2026-10-14;bici;45
El orden es: abrir, intentar leer la primera línea, y mientras lo leído no sea '', procesar y leer la siguiente. Así va con las cuatro primeras vueltas del bucle:
| Vuelta | linea antes de procesar | ¿linea != ''? | Qué se imprime |
|---|---|---|---|
| 1 | '# diario de entrenamientos: fecha;deporte;minutos\n' | sí | el comentario |
| 2 | '2026-10-05;carrera;35\n' | sí | la primera sesión |
| 3 | '2026-10-06;bici;50\n' | sí | la segunda |
| 4 | '\n' | sí | una línea en blanco |
| … | … | … | … |
| 10 | '' | no | nada: se sale del bucle |
Fíjate en la vuelta 4. La línea vacía del archivo no es la string vacía: es '\n', que tiene un carácter. Por eso el bucle no se para ahí. La string vacía '' solo llega cuando ya no hay nada más que leer.
¿Por qué end=»?
Porque la línea ya trae su '\n', y print() añade otro por su cuenta. Mira qué pasa con un print(linea) a secas sobre tres.txt, un archivo de tres sesiones:
# El mismo esquema con print(linea) a secas
f = open('tres.txt', 'r', encoding='utf-8')
linea = f.readline()
while linea != '':
print(linea) # el '\n' de la línea + el '\n' que añade print = línea en blanco
linea = f.readline()
f.close()
Sale una línea en blanco detrás de cada sesión:
2026-10-05;carrera;35 2026-10-06;bici;50 2026-10-08;natación;40
Tienes dos arreglos: print(linea, end='') (no añadas nada) o quitar el salto antes de imprimir con linea.rstrip(). rstrip() quita los '\n', espacios y tabuladores del final; strip() los de los dos extremos; lstrip(), los del principio.
repr(): ver lo que hay de verdad
Cuando un archivo se porta raro, repr() es tu lupa: enseña cada línea como la escribirías en Python, con comillas, '\n' y tabuladores visibles.
# Ver lo que hay de verdad en cada línea
f = open('entrenos.txt', 'r', encoding='utf-8')
linea = f.readline()
while linea != '':
print(repr(linea)) # comillas, '\n', espacios y tabuladores a la vista
linea = f.readline()
print(repr(f.readline())) # ya en el final: readline() devuelve la string vacía
f.close()
Ahora se ve todo:
'# diario de entrenamientos: fecha;deporte;minutos\n' '2026-10-05;carrera;35\n' '2026-10-06;bici;50\n' '\n' '2026-10-08;natación;40\n' '2026-10-09; carrera ;30 \t\n' '2026-10-11;yoga;veinte\n' '2026-10-12;fútbol;90\n' '2026-10-14;bici;45\n' ''
Ahí están los dos espacios y el \t de la sexta línea, que con print() eran invisibles, y la última llamada a readline(), ya en el final, devolviendo ''.
Escribir line = file.readline().rstrip() para leer «ya limpio». Funciona… hasta que el archivo tiene una línea vacía: '\n'.rstrip() es '', y el while cree que el archivo se ha terminado. Lo verás en directo en los ejercicios. Limpia una copia dentro del bucle y deja que la condición mire la línea original.
El archivo como secuencia de líneas: for
Un archivo abierto en lectura se puede recorrer con for, igual que una lista: cada vuelta te da una línea. Es el «esquema general de recorrido» y es la forma más cómoda:
# El archivo como secuencia de líneas: for, sin readline()
f = open('entrenos.txt', 'r', encoding='utf-8')
for numero, linea in enumerate(f, start=1): # numera las líneas desde 1, como un editor
linea = linea.strip() # fuera '\n' y espacios de los dos extremos
if linea == '' or linea.startswith('#'): # ni líneas vacías ni comentarios
continue
fecha, deporte, minutos = linea.split(';') # tres campos separados por ';'
print(numero, fecha, deporte.strip(), minutos) # strip(): ' carrera ' tiene espacios dentro del campo
f.close()
Con enumerate(f, start=1) cada línea viene con su número, como en el editor:
2 2026-10-05 carrera 35 3 2026-10-06 bici 50 5 2026-10-08 natación 40 6 2026-10-09 carrera 30 7 2026-10-11 yoga veinte 8 2026-10-12 fútbol 90 9 2026-10-14 bici 45
linea.strip()quita el'\n'y los espacios y tabuladores de los dos extremos de la línea.if linea == '' or linea.startswith('#'): continuesalta la línea vacía (que tras elstrip()sí es'') y el comentario. Por eso faltan los números 1 y 4.linea.split(';')corta por el separador y da tres campos. Perostrip()solo limpió los extremos de la línea, no los de cada campo:' carrera 'sigue con sus espacios, y por eso hay undeporte.strip().- La sesión de yoga sale con
veinte. De momento solo lo imprimimos; si intentáramosint('veinte'), saltaría unValueError. En la práctica lo tratamos bien.
Un manejador se recorre una sola vez
El cursor avanza al leer y no vuelve solo al principio. Si recorres el mismo f dos veces, la segunda no encuentra nada:
# Recorrer el mismo manejador dos veces
f = open('entrenos.txt', encoding='utf-8') # sin modo: 'r' por omisión
primera = 0
for linea in f:
primera += 1
segunda = 0
for linea in f: # el cursor ya está al final: no queda nada que leer
segunda += 1
f.close()
print('Primera vuelta:', primera, 'líneas')
print('Segunda vuelta:', segunda, 'líneas')
El resultado lo dice todo:
Primera vuelta: 9 líneas Segunda vuelta: 0 líneas
Las 9 líneas del archivo se leen en la primera vuelta y la segunda empieza con el cursor ya al final. Si necesitas recorrerlo otra vez, ciérralo y vuelve a abrirlo (o guarda las líneas en una lista la primera vez).
Leer todo de una vez: read()
read() sin argumentos devuelve todo el archivo en una sola string. Viene bien con archivos pequeños:
# read(): todo el archivo en una sola string
f = open('tres.txt', 'r', encoding='utf-8')
texto = f.read()
f.close()
print(len(texto)) # caracteres, contando cada '\n'
print(texto.count('\n')) # cuántas líneas acaban en '\n'
print(texto.splitlines()) # lista de líneas, ya sin '\n'
Con tres.txt:
64 3 ['2026-10-05;carrera;35', '2026-10-06;bici;50', '2026-10-08;natación;40']
Comprobémoslo a mano. Las líneas son 2026-10-05;carrera;35 (10 + 1 + 7 + 1 + 2 = 21 caracteres), 2026-10-06;bici;50 (10 + 1 + 4 + 1 + 2 = 18) y 2026-10-08;natación;40 (10 + 1 + 8 + 1 + 2 = 22). Más los tres '\n': 21 + 18 + 22 + 3 = 64. Y splitlines() te da la lista de líneas ya sin el salto.
read(n): de n en n caracteres
Con un número, read(n) lee como mucho n caracteres y el cursor avanza. Puedes mezclarlo con readline():
# read(n) lee n caracteres y el cursor avanza
f = open('tres.txt', 'r', encoding='utf-8')
print(repr(f.read(4))) # los 4 primeros caracteres
print(repr(f.read(7))) # los 7 siguientes: sigue donde se quedó
print(repr(f.readline())) # el resto de esa línea
print(repr(f.read())) # todo lo que queda
print(repr(f.read())) # nada: ya estamos al final
f.close()
Cada llamada sigue donde se quedó la anterior:
'2026' '-10-05;' 'carrera;35\n' '2026-10-06;bici;50\n2026-10-08;natación;40\n' ''
read(4) se lleva 2026; read(7) sigue con -10-05; (7 caracteres: -, 1, 0, -, 0, 5, ;); readline() termina esa línea; read() se lleva el resto, y un último read() ya no encuentra nada y devuelve '', igual que readline().
¿Cuándo uso cada forma de leer?
| Quiero… | Uso | Por qué |
|---|---|---|
| procesar línea a línea | for linea in f | lo más claro; no hay que llamar a nada |
| parar en cuanto encuentre algo | readline() + while | controlas tú cuándo seguir |
| el texto entero (contar, buscar con regex) | read() | una sola string; solo para archivos pequeños |
| un número exacto de caracteres | read(n) | formatos de ancho fijo, cabeceras |
Escribir: print(…, file=f) y write()
Para escribir, abre en 'w' o 'a'. Tienes dos herramientas, y se diferencian justo en lo que suele fallar: el salto de línea y el tipo.
# Escribir: print(..., file=f) frente a f.write()
sesiones = [('2026-10-15', 'carrera', 40), ('2026-10-16', 'yoga', 25)]
f = open('con_print.txt', 'w', encoding='utf-8')
for fecha, deporte, minutos in sesiones:
print(fecha, deporte, minutos, sep=';', file=f) # convierte a str y añade el '\n' solo
f.close()
f = open('con_write.txt', 'w', encoding='utf-8')
for fecha, deporte, minutos in sesiones:
n = f.write(f'{fecha};{deporte};{minutos}\n') # escribe EXACTAMENTE esta string
print('write ha escrito', n, 'caracteres') # write devuelve cuántos caracteres escribió
f.close()
for nombre in ['con_print.txt', 'con_write.txt']:
f = open(nombre, 'r', encoding='utf-8')
print(nombre, repr(f.read()))
f.close()
Los dos archivos acaban igual, pero no por el mismo camino:
write ha escrito 22 caracteres write ha escrito 19 caracteres con_print.txt '2026-10-15;carrera;40\n2026-10-16;yoga;25\n' con_write.txt '2026-10-15;carrera;40\n2026-10-16;yoga;25\n'
print(fecha, deporte, minutos, sep=';', file=f)hace lo de siempre pero en el archivo: convierte cada cosa a texto (el40es uninty no pasa nada), las separa consepy **añade el'\n'al final**.f.write(texto)escribe exactamente la string que le das. Nada más. Ni separadores, ni salto, ni conversiones. Devuelve cuántos caracteres escribió: 22 para'2026-10-15;carrera;40\n'(10 + 1 + 7 + 1 + 2 + 1 = 22) y 19 para la de yoga (10 + 1 + 4 + 1 + 2 + 1 = 19).
Si se te olvida el '\n' con write(), las sesiones se pegan:
# write() sin '\n': todo acaba en la misma línea
f = open('pegado.txt', 'w', encoding='utf-8')
f.write('2026-10-15;carrera;40')
f.write('2026-10-16;yoga;25')
f.close()
f = open('pegado.txt', 'r', encoding='utf-8')
print(repr(f.read()))
f.close()
Una sola línea con las dos sesiones, sin salto entre 40 y 2026:
'2026-10-15;carrera;402026-10-16;yoga;25'
f.write(minutos) con un número. write() solo acepta strings y lanza TypeError: write() argument must be str, not int. Conviértelo con str(minutos) o, mejor, monta la línea con una f-string.
En el esquema de escritura, el bucle recorre el origen de los datos (la lista, otro archivo…), no el archivo que estás escribiendo, que es solo el destino.
La cláusula with
Olvidarse del close() es facilísimo, y si el programa falla antes de llegar a él, el archivo se queda abierto (y lo escrito puede no haberse guardado del todo). with lo arregla: abre el archivo, te da el manejador y lo cierra solo al salir del bloque, pase lo que pase dentro.
# with cierra el archivo al salir del bloque, pase lo que pase
total = 0
with open('entrenos.txt', 'r', encoding='utf-8') as f:
for linea in f:
partes = linea.strip().split(';')
if len(partes) == 3 and partes[2].isdigit(): # solo líneas con minutos válidos
total += int(partes[2])
print('¿Cerrado dentro del with?', f.closed)
print('¿Cerrado fuera del with?', f.closed)
print('Minutos válidos:', total)
Mira el estado del manejador dentro y fuera:
¿Cerrado dentro del with? False ¿Cerrado fuera del with? True Minutos válidos: 290
Dentro del with, f.closed es False; en cuanto la indentación vuelve atrás, es True, sin haber escrito ningún close(). Los 290 minutos salen de 35 + 50 + 40 + 30 + 90 + 45 = 290: el comentario y la línea vacía no tienen tres campos, y 'veinte'.isdigit() es False. La línea de los espacios sí cuenta, porque strip() deja '30' limpio.
Desde hoy, abre siempre con with. Puedes abrir dos archivos en el mismo: with open('a.txt') as fin, open('b.txt', 'w') as fout:. Lo usaremos para copiar y filtrar.
La codificación: encoding=’utf-8′
Por dentro, un archivo son bytes. Un archivo de texto guarda caracteres codificados según una norma, y para leerlos bien hay que usar la misma norma con la que se escribieron. Hoy lo normal es UTF-8, donde la á ocupa dos bytes. Si lees con otra codificación, esos dos bytes se interpretan como dos caracteres distintos:
# La misma línea leída con la codificación buena y con otra
with open('ruta.txt', 'w', encoding='utf-8') as f:
f.write('Ruta en bici hasta Gáldar\n')
with open('ruta.txt', 'r', encoding='utf-8') as f:
print(repr(f.read())) # la misma codificación con la que se escribió
with open('ruta.txt', 'r', encoding='latin-1') as f:
print(repr(f.read())) # otra codificación: la 'á' (2 bytes en UTF-8) sale como 2 caracteres raros
La misma línea, leída de dos formas:
'Ruta en bici hasta Gáldar\n' 'Ruta en bici hasta Gáldar\n'
Ese Gáldar es el clásico texto «roto» que habrás visto en alguna web. En muchos Windows la codificación por defecto no ha sido UTF-8, así que un open('x.txt') sin encoding puede leer mal los acentos de un archivo que en otro ordenador se ve perfecto.
Pon siempre encoding='utf-8' al leer y al escribir. Es un argumento más y te ahorra el problema en todos los ordenadores.
El módulo os: rutas, carpetas y archivos
El módulo os te deja hablar con el sistema operativo: comprobar si algo existe, crear carpetas, unir rutas, listar y borrar. Hay que importarlo con import os.
# El módulo os: rutas, carpetas y archivos
import os
print(os.path.exists('entrenos.txt')) # True: está en la carpeta de trabajo
print(os.path.exists('entrenos2025.txt')) # False: así se comprueba ANTES de abrir con 'r'
os.makedirs('copias/2026', exist_ok=True) # crea también la carpeta intermedia; exist_ok: sin error si ya existe
ruta = os.path.join('copias', '2026', 'octubre.txt') # une las partes con el separador del sistema
print(ruta)
with open(ruta, 'w', encoding='utf-8') as f:
f.write('copia de prueba\n')
print(os.listdir(os.path.join('copias', '2026'))) # lo que hay dentro de la carpeta
print(os.path.isdir('copias'), os.path.isdir(ruta)) # carpeta sí, archivo no
os.remove(ruta) # borra el archivo (sin papelera)
print(os.listdir(os.path.join('copias', '2026')))
Paso a paso:
True False copias/2026/octubre.txt ['octubre.txt'] True False []
os.path.exists(ruta):TrueoFalse. Es la forma de evitar elFileNotFoundErrorantes de abrir en'r'(o de no machacar algo en'w').os.makedirs('copias/2026', exist_ok=True): crea la carpeta y las intermedias que falten. Conexist_ok=Trueno da error si ya existen (os.mkdircrea solo una y falla si ya está).os.path.join('copias', '2026', 'octubre.txt'): une las partes con el separador del sistema. Aquí, en Linux, saliócopias/2026/octubre.txt; en Windows saldríacopias\2026\octubre.txt. Por eso no se escriben las barras a mano.os.listdir(carpeta): lista lo que hay dentro.os.path.isdir(): ¿es una carpeta?os.remove(ruta): borra el archivo, sin papelera. Después, la lista sale vacía.
Hay más: os.getcwd() te dice la carpeta de trabajo (útil para el error de antes), os.chdir() la cambia y os.rmdir() borra una carpeta vacía.
Errores típicos con archivos
Abrir con 'w' para «añadir». Vacía el archivo al abrir. Para añadir, 'a'.
print(linea) con líneas leídas del archivo: salen líneas en blanco entre medias. Usa end='' o rstrip().
Recorrer dos veces el mismo manejador. La segunda vuelta no lee nada: el cursor está al final.
write() sin '\n' (todo en una línea) o con un número (TypeError).
Olvidar close(). Con with no puede pasar.
Míralo paso a paso en Python Tutor
Python Tutor ejecuta tu código línea a línea y dibuja las variables. Elige Python 3. Tiene una limitación: no abre archivos de tu disco. Así que simulamos el archivo con una string y iter(...): cada next(f, '') hace de readline() y devuelve '' cuando no quedan líneas.
# Python Tutor no abre archivos de tu disco: el "archivo" es una string con sus '\n'
texto = '2026-10-05;carrera;35\n\n2026-10-06;bici;50\n'
f = iter(texto.splitlines(keepends=True)) # cada next() da una línea con su '\n', como readline()
total = 0
linea = next(f, '') # '' cuando ya no quedan líneas, igual que readline()
while linea != '':
limpia = linea.strip() # limpio una copia; la condición sigue mirando la línea original
if limpia != '':
fecha, deporte, minutos = limpia.split(';')
total += int(minutos)
linea = next(f, '')
print('Total:', total, 'min')
La salida que verás al final:
Total: 85 min
Qué observar:
- En el paso en que se crea
f, mira la lista de líneas: cada una **lleva su'\n'**, y la segunda es solo'\n'. - En la segunda vuelta,
lineavale'\n': la condición delwhileesTrue(no es''), perolimpiavale''y elifse la salta. - Mira cómo
totalpasa de 0 a 35 y de 35 a 85 (35 + 50 = 85): solo cambia en las vueltas con sesión. - En la última llamada,
next(f, '')devuelve''y el bucle termina. Es exactamente lo que hacereadline()al final del archivo.
Resumen
| Concepto | Lo esencial |
|---|---|
| Archivo de texto | secuencia de caracteres o de líneas acabadas en '\n' |
open(nombre, modo, encoding='utf-8') | devuelve el manejador; luego close() |
'r' / 'w' / 'a' | leer (debe existir) / escribir (vacía) / añadir al final |
readline() | una línea con su '\n'; '' al final del archivo |
for linea in f | recorrido línea a línea; una sola vez por apertura |
read() / read(n) | todo en una string / n caracteres |
print(..., file=f) | convierte, separa y añade '\n' |
f.write(s) | escribe solo strings y exactamente lo que le das |
with | cierra el archivo solo |
os | exists, makedirs, join, listdir, remove |
Tres ideas para llevarte:
- Una línea vacía es
'\n', no''. La string vacía solo significa «se acabó el archivo». 'w'borra,'a'añade. Elige el modo pensando en lo que ya hay en el archivo.print()pone el salto por ti;write()no pone nada. Y abre siempre conwithyencoding='utf-8'.
Ahora toca usarlo de verdad: en la práctica de archivos de texto leemos el diario completo con sus líneas raras, apuntamos sesiones sin borrar nada y escribimos un informe del mes en un archivo nuevo. Y con este tema cierras el temario de FP1: ¡enhorabuena!
Siguiente paso: prácticaArchivos de texto en Python — práctica con el resumen del diario, sesiones que se apuntan sin borrar nada y un informe del mes (y la sesión que se pegó a la del día anterior)¿Te ha servido este artículo? Así puedes apoyar SergioLearns →

2 comentarios