Los archivos temporales aparecen en exportaciones, cargas, pruebas, conversiones, descargas, procesamiento de imágenes y comunicación con programas externos. Crearlos manualmente en una carpeta fija parece sencillo, pero puede causar colisiones de nombres, permisos débiles, datos abandonados y vulnerabilidades de carrera. El módulo tempfile en Python ofrece APIs seguras y portables para archivos y directorios temporales con limpieza automática.
Esta guía explica TemporaryFile, NamedTemporaryFile, SpooledTemporaryFile, TemporaryDirectory, mkstemp() y mkdtemp(), además de diferencias entre Windows y Unix, modos binario y texto, nombres visibles, limpieza, pruebas y seguridad. Complementa nuestros artículos sobre listas en Python, slicing, la sentencia with, FileNotFoundError y archivos ZIP seguros.
Por qué no crear nombres temporales manualmente
Un código como open('/tmp/salida.txt', 'w') puede funcionar en una prueba aislada, pero es frágil en producción. Dos procesos pueden elegir el mismo nombre, otro proceso puede crear un archivo o enlace antes que tu programa y una ruta fija puede no existir o no tener permisos en otra plataforma.
tempfile combina la elección segura del nombre y la creación en una sola operación. Los nombres incorporan caracteres aleatorios y los permisos siguen reglas apropiadas para el usuario que crea el recurso.
TemporaryFile para almacenamiento simple
TemporaryFile() devuelve un objeto similar a un archivo. El modo predeterminado es binario de lectura y escritura, w+b, y el recurso se elimina al cerrarse.
from tempfile import TemporaryFile
with TemporaryFile() as archivo:
archivo.write(b"resultado temporal")
archivo.seek(0)
datos = archivo.read()
print(datos)El bloque with garantiza cierre y limpieza incluso si ocurre una excepción. En Unix, el archivo puede no tener una entrada visible en el directorio. Otras plataformas pueden usar internamente un archivo con nombre. No hagas depender la lógica de si existe un camino visible.
Modo texto y codificación
Para contenido textual, declara el modo y la codificación explícitamente.
from tempfile import TemporaryFile
with TemporaryFile(mode="w+t", encoding="utf-8") as archivo:
archivo.write("Hola, archivo temporal!\n")
archivo.seek(0)
print(archivo.read())Los parámetros explícitos evitan diferencias de codificación entre máquinas. Conserva el modo binario para imágenes, PDFs, ZIPs y datos de red.
NamedTemporaryFile cuando necesitas una ruta
Algunas bibliotecas y herramientas de línea de comandos aceptan solo un nombre de archivo. NamedTemporaryFile() crea una ruta visible y la expone mediante name.
from tempfile import NamedTemporaryFile
with NamedTemporaryFile(suffix=".json") as archivo:
print(archivo.name)
archivo.write(b'{"estado": "ok"}')
archivo.flush()
# pasa archivo.name a otra APIEl sufijo resulta útil cuando una herramienta detecta el formato por la extensión. También puedes definir prefix y dir; usa argumentos con nombre para mejorar la legibilidad.
delete y delete_on_close
De forma predeterminada, un archivo temporal con nombre se elimina al cerrarse. Desde Python 3.12, delete_on_close permite separar el cierre del objeto de la eliminación al salir del contexto.
from tempfile import NamedTemporaryFile
with NamedTemporaryFile(
mode="w+b",
suffix=".bin",
delete=True,
delete_on_close=False,
) as archivo:
ruta = archivo.name
archivo.write(b"datos")
archivo.close()
with open(ruta, "rb") as lectura:
print(lectura.read())
# eliminado al salir del contexto exteriorEste patrón ayuda cuando otra biblioteca debe reabrir el archivo por nombre. Si usas delete=False, la aplicación asume toda la responsabilidad de limpieza.
Diferencias importantes en Windows
Los sistemas POSIX suelen permitir reabrir o eliminar un archivo mientras sigue abierto. Windows aplica reglas más estrictas de compartición y acceso de borrado. Reabrir un NamedTemporaryFile aún abierto puede fallar según delete, delete_on_close y cómo se cree el segundo descriptor.
Una estrategia predecible consiste en usar delete_on_close=False, cerrar el objeto original antes de reabrir por nombre y cerrar todos los demás descriptores antes de salir del contexto. Prueba el flujo en el mismo sistema operativo de producción.
TemporaryDirectory para un espacio completo
Cuando un trabajo usa varios archivos, crea un directorio temporal aislado.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory(prefix="informe-") as carpeta:
raiz = Path(carpeta)
entrada = raiz / "entrada.csv"
salida = raiz / "salida.json"
entrada.write_text("nombre,valor\nA,10\n", encoding="utf-8")
salida.write_text('{"total": 10}', encoding="utf-8")
print(list(raiz.iterdir()))
# carpeta y contenido eliminadosEl valor del contexto contiene la ruta y la limpieza es recursiva. Es ideal para pruebas de importación, extracción controlada, conversión multimedia y procesos de compilación.
delete e ignore_cleanup_errors
TemporaryDirectory acepta ignore_cleanup_errors para una limpieza de mejor esfuerzo, útil cuando Windows conserva un archivo abierto. Desde Python 3.12, delete=False puede preservar el árbol después de salir del contexto para depuración.
from tempfile import TemporaryDirectory
with TemporaryDirectory(delete=False) as carpeta:
print("Conservada para inspección:", carpeta)No mantengas esta opción en producción sin una política de retención. Los directorios abandonados pueden llenar el disco.
SpooledTemporaryFile: memoria antes del disco
SpooledTemporaryFile mantiene datos en memoria hasta superar max_size o hasta que una operación como fileno() exija un archivo real. Después realiza el rollover al disco.
from tempfile import SpooledTemporaryFile
with SpooledTemporaryFile(max_size=1024 * 1024) as archivo:
archivo.write(b"contenido pequeño")
archivo.seek(0)
print(archivo.read())Esta clase funciona bien para uploads, respuestas generadas y transformaciones que normalmente son pequeñas, pero pueden crecer. Combina velocidad en memoria con una salida segura al disco.
Forzar rollover
Llama a rollover() cuando otra API requiera un descriptor real.
with SpooledTemporaryFile(max_size=10_000) as archivo:
archivo.write(b"abc")
archivo.rollover()
print(archivo.fileno())No dependas del atributo interno _file. Usa la interfaz pública de archivo.
mkstemp(): API de bajo nivel
mkstemp() crea un archivo de forma segura y devuelve un descriptor del sistema operativo junto con una ruta absoluta.
import os
from tempfile import mkstemp
fd, ruta = mkstemp(suffix=".txt", prefix="proceso-")
try:
with os.fdopen(fd, "w", encoding="utf-8") as archivo:
archivo.write("contenido")
finally:
if os.path.exists(ruta):
os.unlink(ruta)La función no elimina el archivo automáticamente. Cerrar el descriptor no borra la ruta. Prefiere context managers de alto nivel salvo que necesites control del descriptor.
mkdtemp(): limpieza manual del directorio
mkdtemp() crea un directorio seguro y devuelve una ruta absoluta. Tu código debe eliminar el árbol.
import shutil
from pathlib import Path
from tempfile import mkdtemp
carpeta = Path(mkdtemp(prefix="job-"))
try:
(carpeta / "resultado.txt").write_text("ok", encoding="utf-8")
finally:
shutil.rmtree(carpeta, ignore_errors=False)Cuando la limpieza automática es válida, TemporaryDirectory es más simple y menos propenso a fugas.
Nunca uses mktemp()
La documentación oficial de tempfile marca mktemp() como obsoleto e inseguro. Genera un nombre que no existía al llamar, pero no crea el archivo inmediatamente. Otro proceso puede ocuparlo antes de la apertura.
Usa NamedTemporaryFile o mkstemp(), que eligen el nombre y crean el recurso de forma atómica.
Elegir prefix, suffix y dir
prefix ayuda a identificar recursos durante depuración, suffix conserva una extensión necesaria y dir controla la ubicación.
with NamedTemporaryFile(
prefix="miniatura-",
suffix=".png",
dir="/ruta/controlada",
) as imagen:
passEl directorio debe existir y permitir escritura. No construyas prefijos a partir de entrada no confiable. Aunque la parte aleatoria sea segura, un texto malicioso puede confundir registros o herramientas.
Encontrar el directorio temporal predeterminado
gettempdir() devuelve el directorio seleccionado. Python considera variables como TMPDIR, TEMP y TMP, seguidas por ubicaciones específicas de la plataforma.
from tempfile import gettempdir
print(gettempdir())No supongas que siempre será /tmp. Contenedores, servicios y sistemas empresariales pueden redirigir temporales a otro volumen. Evita cambiar globalmente tempfile.tempdir; pasa dir a la operación concreta.
flush, seek y visibilidad
Después de escribir, usa seek(0) antes de leer del mismo flujo. Si otro proceso abrirá la misma ruta, llama primero a flush() para enviar los buffers de Python al sistema operativo.
with NamedTemporaryFile() as archivo:
archivo.write(b"123")
archivo.flush()
archivo.seek(0)
assert archivo.read() == b"123"os.fsync() solicita una persistencia más fuerte, pero rara vez tiene sentido para datos temporales y tiene un coste adicional.
Almacenamiento temporal para uploads
No mantengas uploads ilimitados completamente en memoria. Un diseño práctico transmite el flujo a SpooledTemporaryFile, impone un límite, valida el formato real, procesa y limpia al terminar.
Temporal no significa confiable. Continúa aplicando límites, antivirus cuando sea necesario, validación de contenido y protección contra bombas de descompresión o archivos malformados.
Uso con subprocesos
Si un programa acepta entrada estándar, una tubería evita crear una ruta. Cuando exige un nombre, usa NamedTemporaryFile o TemporaryDirectory, cierra y ejecuta flush según la plataforma, pasa la ruta como argumento separado y nunca construyas comandos de shell por concatenación.
Cuando la limpieza sea manual, colócala en finally. Un proceso externo fallido no debe dejar datos sensibles en el disco.
Pruebas con TemporaryDirectory
Los directorios temporales hacen que las pruebas sean independientes de la máquina.
from pathlib import Path
from tempfile import TemporaryDirectory
def guardar(ruta, texto):
Path(ruta).write_text(texto, encoding="utf-8")
with TemporaryDirectory() as carpeta:
destino = Path(carpeta) / "prueba.txt"
guardar(destino, "valor")
assert destino.read_text(encoding="utf-8") == "valor"Cada prueba recibe un espacio aislado, reduce colisiones y no ensucia el repositorio. Los frameworks ofrecen fixtures similares, pero conocer tempfile sigue siendo útil en scripts y pruebas sin dependencias.
Seguridad y datos sensibles
El módulo crea nombres de forma segura, pero la aplicación aún debe controlar permisos, tiempo de retención y registros. No escribas rutas con identificadores sensibles en logs. Evita volúmenes compartidos sin aislamiento y considera cifrado cuando el modelo de amenazas lo exija.
En POSIX, una terminación abrupta con SIGKILL puede impedir la limpieza de archivos con nombre. Los servicios de larga duración deberían vigilar el espacio y eliminar residuos legítimos por edad y propietario.
Errores frecuentes
- Usar nombres fijos en directorios compartidos.
- Elegir
mktemp()porque devuelve solo una ruta. - Olvidar
seek(0)antes de leer. - No usar
flush()antes de que otro proceso abra el archivo. - Suponer comportamiento POSIX en Windows.
- Usar
delete=Falsesin limpiar después. - Mantener uploads ilimitados en memoria.
- Suponer que el directorio temporal siempre es
/tmp.
Buenas prácticas
- Prefiere context managers y APIs de alto nivel.
- Usa
TemporaryFilecuando no necesitas una ruta. - Usa
NamedTemporaryFilecuando otra API exige un nombre. - Usa
TemporaryDirectorypara varios artefactos. - Usa
SpooledTemporaryFilepara contenido pequeño con límite. - Prueba la reapertura en Windows.
- Impone límites de tamaño y políticas de retención.
- Consulta la documentación oficial de pathlib.
Conclusión
El módulo tempfile en Python elimina gran parte del trabajo peligroso del almacenamiento temporal. Genera nombres resistentes a colisiones, crea recursos de forma segura, ofrece limpieza automática y funciona de manera consistente en plataformas soportadas.
La clase adecuada depende de la integración: TemporaryFile para un flujo descartable, NamedTemporaryFile para herramientas que necesitan una ruta, SpooledTemporaryFile para equilibrar memoria y disco y TemporaryDirectory para procesos con varios archivos. Con context managers, límites, pruebas multiplataforma y limpieza predecible, el almacenamiento temporal deja de ser una fuente de fugas, fallos de permisos y errores de seguridad.







