Escribir y Crear Archivos en Python
Aprende a escribir archivos en Python: write(), writelines(), modo append, escritura binaria, pathlib y patrones seguros con bloques with.
Escribir archivos es una de las operaciones de E/S más fundamentales en Python. Ya sea que guardes la salida de un programa, persistas configuraciones, exportes datos a CSV o registres eventos, necesitas una forma confiable de crear y actualizar archivos. Este capítulo cubre todos los enfoques que ofrece Python: write(), writelines(), modo append, escrituras binarias, manejo de saltos de línea, codificación de caracteres, la API moderna de pathlib y patrones para escribir de forma segura sin pérdida de datos.
Abrir un Archivo para Escritura
Toda operación de escritura de archivos comienza con la función integrada open(). El segundo argumento — el modo — controla lo que ocurre al abrir el archivo:
| Modo | Significado | El archivo existe | El archivo no existe |
|---|---|---|---|
"w" | Escritura (texto) | Trunca (borra) el archivo | Crea un nuevo archivo |
"a" | Append (texto) | Mueve el puntero al final | Crea un nuevo archivo |
"x" | Creación exclusiva | Lanza FileExistsError | Crea un nuevo archivo |
"wb" | Escritura (binaria) | Trunca el archivo | Crea un nuevo archivo |
"ab" | Append (binaria) | Mueve el puntero al final | Crea un nuevo archivo |
"r+" | Lectura + escritura | Abre en su lugar | Lanza FileNotFoundError |
Lo más importante a recordar sobre el modo "w": borra silenciosamente el archivo completo antes de escribir. Si solo deseas agregar contenido a un archivo existente, usa el modo "a" (append) en su lugar.
Siempre proporciona el parámetro encoding al escribir archivos de texto para que tu código se comporte de manera idéntica en Windows, macOS y Linux:
file = open("output.txt", "w", encoding="utf-8")Usa Siempre un Bloque with
Llamar a open() sin un bloque with significa que debes llamar a file.close() tú mismo. Olvidar cerrar un archivo provoca que los datos en el buffer nunca se escriban en disco, errores de demasiados archivos abiertos en scripts de larga ejecución y corrupción de archivos en algunos sistemas operativos.
La sentencia with (un gestor de contexto) resuelve todos estos problemas. Python cierra el archivo automáticamente cuando el bloque termina — incluso si se lanza una excepción dentro del bloque.
with open("output.txt", "w", encoding="utf-8") as f:
f.write("Hello, World!\n")
# File is closed and flushed here — guaranteedTodos los ejemplos de este capítulo usan la sentencia with. Evita el patrón manual de open() / close().
Escribir Texto con write()
file.write(string) escribe la cadena dada en el archivo y devuelve el número de caracteres escritos. No agrega un salto de línea automáticamente — debes incluir \n tú mismo.
Escribir una sola línea en un nuevo archivo
with open("greeting.txt", "w", encoding="utf-8") as f:
chars_written = f.write("Hello, World!\n")
print(chars_written) # 14Escribir múltiples líneas llamando a write() repetidamente
with open("poem.txt", "w", encoding="utf-8") as f:
f.write("Roses are red,\n")
f.write("Violets are blue,\n")
f.write("Python is great,\n")
f.write("And so are you.\n")Cada llamada a write() agrega contenido al archivo en la posición actual. El archivo se escribe desde cero (cualquier contenido anterior se pierde) porque se usó el modo "w".
Escribir Múltiples Líneas con writelines()
file.writelines(iterable) acepta cualquier iterable de cadenas — una lista, un generador o una tupla — y escribe cada elemento en secuencia. Al igual que write(), no agrega saltos de línea entre elementos.
Escribir una lista de líneas
lines = [
"First line\n",
"Second line\n",
"Third line\n",
]
with open("lines.txt", "w", encoding="utf-8") as f:
f.writelines(lines)Si tus datos de origen no contienen ya \n, agrégalo antes de escribir:
data = ["Alice", "Bob", "Charlie"]
with open("names.txt", "w", encoding="utf-8") as f:
f.writelines(name + "\n" for name in data)La expresión generadora name + "\n" for name in data es eficiente en memoria: Python produce cada cadena a demanda en lugar de construir toda la lista en memoria primero.
write() vs writelines() — Cuándo Usar Cada Uno
write() | writelines() | |
|---|---|---|
| Entrada | Una sola cadena | Cualquier iterable de cadenas |
| Saltos de línea | Tú controlas cada \n | Tú controlas cada \n |
| Mejor para | Construir la salida incrementalmente | Escribir una secuencia pre-construida de una vez |
Crear un Archivo que No Debe Existir
Usa el modo "x" (creación exclusiva) cuando deseas que Python cree un nuevo archivo y falle si el archivo ya existe. Esto evita sobrescribir accidentalmente datos importantes.
try:
with open("config.txt", "x", encoding="utf-8") as f:
f.write("host=localhost\n")
f.write("port=8080\n")
except FileExistsError:
print("config.txt already exists — not overwriting.")Este patrón es útil para generar archivos de salida únicos (registros, exportaciones, instantáneas) donde una colisión indica que algo salió mal.
Agregar Contenido a un Archivo Existente
Abrir un archivo con el modo "a" mueve el puntero de escritura al final del archivo. El nuevo contenido se agrega después del contenido existente; nada se borra.
Agregar una entrada de registro a un archivo existente
import datetime
with open("app.log", "a", encoding="utf-8") as f:
timestamp = datetime.datetime.now().isoformat()
f.write(f"[{timestamp}] Server started\n")Si app.log no existe aún, Python lo crea. Si ya existe, la nueva línea se agrega al final. Ejecutar el script varias veces construye un registro en crecimiento.
Escritura vs Append — Elegir el Modo Correcto
- Usa
"w"cuando quieras reemplazar completamente el contenido del archivo (generar un informe nuevo, guardar una nueva configuración). - Usa
"a"cuando quieras agregar al contenido existente (registros, acumulación de resultados en múltiples ejecuciones).
Saltos de Línea y Terminaciones de Línea
El modo de texto de Python ("w", "a", "r") traduce el salto de línea universal \n a la terminación de línea nativa de la plataforma al escribir:
- Windows:
\n→\r\n(CRLF) - macOS / Linux:
\npermanece\n(LF)
Este suele ser el comportamiento correcto — los archivos escritos en Windows se abren correctamente en el Bloc de notas.
Si necesitas forzar una terminación de línea específica independientemente de la plataforma — por ejemplo, al generar archivos que deben ser leídos por un sistema específico — pasa el parámetro newline:
# Force Unix-style LF on all platforms (e.g. for Linux-target files)
with open("unix_file.txt", "w", encoding="utf-8", newline="\n") as f:
f.write("line one\n")
f.write("line two\n")
# Preserve line endings exactly as given (no translation at all)
with open("raw.txt", "w", encoding="utf-8", newline="") as f:
f.write("line one\r\n")
f.write("line two\n")Codificación de Caracteres
Siempre especifica encoding= al escribir archivos de texto. Depender del valor predeterminado de la plataforma arriesga crear archivos que no puedan leerse en otros sistemas.
Codificaciones recomendadas para escenarios comunes:
| Codificación | Usar cuando |
|---|---|
"utf-8" | Uso general; funciona para todos los idiomas; predeterminado para la mayoría de proyectos Python |
"utf-8-sig" | UTF-8 con BOM — útil para archivos que se abrirán en Excel en Windows |
"latin-1" | Archivos heredados de Europa Occidental |
"cp1252" | Texto ANSI de Windows |
Escribir un archivo con codificación UTF-8
with open("international.txt", "w", encoding="utf-8") as f:
f.write("English: Hello\n")
f.write("Japanese: こんにちは\n")
f.write("Arabic: مرحبا\n")Escribir Archivos Binarios
Abre un archivo con el modo "wb" (escritura binaria) para escribir bytes crudos en lugar de cadenas. El modo binario es necesario para imágenes, audio, archivos comprimidos, ejecutables y cualquier dato que no sea texto. No especifiques encoding en modo binario.
Escribir bytes en un archivo binario
data = bytes([0x89, 0x50, 0x4E, 0x47]) # PNG magic bytes
with open("header.bin", "wb") as f:
f.write(data)
print(f.write(b"\r\n\x1a\n")) # 4Copiar un archivo binario
with open("photo.jpg", "rb") as src:
content = src.read()
with open("photo_backup.jpg", "wb") as dst:
dst.write(content)Para archivos binarios grandes, lee y escribe en fragmentos para evitar cargar todo el archivo en memoria:
CHUNK = 65536 # 64 KB
with open("large.bin", "rb") as src, open("large_copy.bin", "wb") as dst:
while True:
chunk = src.read(CHUNK)
if not chunk:
break
dst.write(chunk)Manejo de Errores al Escribir
Un script de calidad de producción siempre anticipa las formas en que puede fallar la escritura de un archivo.
Manejar errores comunes de escritura
try:
with open("/etc/protected.txt", "w", encoding="utf-8") as f:
f.write("data\n")
except PermissionError:
print("Error: you do not have write permission for this file.")
except FileNotFoundError:
print("Error: one or more directories in the path do not exist.")
except IsADirectoryError:
print("Error: the path points to a directory, not a file.")
except OSError as e:
print(f"OS error: {e}")Excepciones comunes que encontrarás:
| Excepción | Cuándo ocurre |
|---|---|
PermissionError | El proceso carece de permiso de escritura |
FileNotFoundError | Un directorio intermedio en la ruta no existe |
FileExistsError | Modo "x" y el archivo ya existe |
IsADirectoryError | La ruta apunta a un directorio |
OSError | Disco lleno, error de sistema de archivos en red y otros problemas a nivel del sistema operativo |
Consulta Python Try Except para una guía completa sobre el manejo de excepciones.
Escribir Archivos de Forma Segura (Patrón de Escritura Atómica)
Un simple open("file.txt", "w") no es seguro para datos críticos: si tu script falla o se interrumpe a mitad de la escritura, el archivo queda en un estado parcialmente escrito y corrupto. La solución estándar es una escritura atómica: escribe primero en un archivo temporal y luego renómbralo sobre el destino.
import os
import tempfile
def write_file_safely(path, content, encoding="utf-8"):
"""Write content to path atomically using a temp file + rename."""
dir_name = os.path.dirname(os.path.abspath(path)) or "."
# Write to a temp file in the same directory (same filesystem = atomic rename)
fd, tmp_path = tempfile.mkstemp(dir=dir_name)
try:
with os.fdopen(fd, "w", encoding=encoding) as f:
f.write(content)
os.replace(tmp_path, path) # atomic on POSIX; best-effort on Windows
except Exception:
os.unlink(tmp_path) # clean up if something went wrong
raise
write_file_safely("important.txt", "critical data\n")os.replace() (Python 3.3+) reemplaza el destino atómicamente en sistemas POSIX: los lectores ven el archivo antiguo o el nuevo, nunca una escritura parcial.
Escribir Archivos con pathlib
pathlib.Path (introducido en Python 3.4) proporciona una API concisa y orientada a objetos. Para escrituras simples de una sola vez, Path.write_text() y Path.write_bytes() son más legibles que open().
Path.write_text()
from pathlib import Path
Path("output.txt").write_text("Hello from pathlib!\n", encoding="utf-8")write_text() abre el archivo en modo "w", escribe la cadena y cierra el archivo — todo en una sola llamada. Siempre sobreescribe el archivo. No hay un equivalente de append; para agregar contenido usa open() con modo "a".
Path.write_bytes()
from pathlib import Path
Path("data.bin").write_bytes(b"\x00\x01\x02\x03")Construir Rutas con pathlib
pathlib también facilita la construcción de rutas de forma segura sin concatenación de cadenas:
from pathlib import Path
output_dir = Path("results")
output_dir.mkdir(exist_ok=True) # create the directory if needed
report_path = output_dir / "report.txt"
report_path.write_text("Run complete.\n", encoding="utf-8")
print(report_path) # results/report.txt
print(report_path.exists()) # TrueEl operador / en objetos Path une segmentos de ruta — sin necesidad de os.path.join().
Ejemplo Práctico: Escribir un Informe CSV
El siguiente ejemplo completo escribe una lista de registros en un archivo CSV usando solo herramientas integradas (sin el módulo csv), demostrando varios conceptos de este capítulo juntos.
from pathlib import Path
import datetime
def write_csv_report(path, headers, rows):
"""Write a simple CSV file with a header row."""
with open(path, "w", encoding="utf-8", newline="") as f:
f.write(",".join(headers) + "\n")
for row in rows:
f.write(",".join(str(v) for v in row) + "\n")
records = [
("Alice", 30, "Engineering"),
("Bob", 25, "Marketing"),
("Charlie", 35, "Finance"),
]
output = Path("staff_report.txt")
write_csv_report(output, ["Name", "Age", "Department"], records)
print(output.read_text(encoding="utf-8"))Salida esperada:
Name,Age,Department
Alice,30,Engineering
Bob,25,Marketing
Charlie,35,FinanceNota que newline="" se pasa a open() para que Python no traduzca doblemente las terminaciones de línea dentro de las filas CSV — esto coincide con la recomendación en la documentación del módulo csv de Python.
Para casos más complejos (comillas, dialectos, casos extremos de Unicode) usa el módulo integrado Python CSV en su lugar.
Referencia Rápida
| Objetivo | Patrón de código |
|---|---|
| Crear o sobreescribir un archivo | open("f.txt", "w", encoding="utf-8") |
| Agregar contenido a un archivo | open("f.txt", "a", encoding="utf-8") |
| Crear solo si es nuevo | open("f.txt", "x", encoding="utf-8") |
| Escribir datos binarios | open("f.bin", "wb") |
| Escribir una cadena | f.write("text\n") |
| Escribir una lista de cadenas | f.writelines(lines) |
| Escritura de texto en una sola llamada | Path("f.txt").write_text("...", encoding="utf-8") |
| Escritura binaria en una sola llamada | Path("f.bin").write_bytes(b"...") |
| Escritura segura / atómica | Escribe en archivo temporal, luego os.replace() |
Capítulos Relacionados
- Python File Handling — modos de apertura, parámetros de
open()y la sentenciawith - Python Read Files —
read(),readline(),readlines(), iteración de líneas yseek() - Python Delete Files — eliminar archivos y directorios de forma segura
- Python Try Except — manejo de excepciones en Python
- Python CSV — leer y escribir archivos CSV con el módulo
csv - Python JSON — serializar datos en archivos JSON