tempfile — Objetos temporales del sistema de archivos¶
Propósito: | Crea objetos temporales del sistema de archivos. |
---|
Crear archivos temporales con nombres únicos de forma segura, que no pueden ser
adivinados por alguien que quiere romper la aplicación o robar los datos, es un
reto. El módulo tempfile
proporciona varias funciones para crear de forma
segura los recursos temporales del sistema de archivos. TemporaryFile()
abre y devuelve un archivo sin nombre, NamedTemporaryFile()
abre y devuelve
un archivo con nombre, SpooledTemporaryFile
guarda su contenido en la
memoria antes escribirlo en el disco, y TemporaryDirectory
es un gestor de
contexto que elimina el directorio cuando se cierra el contexto.
Archivos temporales¶
Aplicaciones que necesitan archivos temporales para almacenar datos, sin
necesidad de compartir ese archivo con otros programas, debe usar la función
TemporaryFile()
para crear los archivos. La función crea un archivo, y en
las plataformas donde es posible, lo desvincula inmediatamente. Esto hace que
sea imposible que otro programa encuentre o abra el archivo, ya que no hay
ninguna referencia a él en el sistema de archivos. El archivo creado por
TemporaryFile()
se elimina automáticamente cuando se cierra, ya sea
llamando a close()
o usando la interfaz del gestor de contexto y la
declaración with
.
import os
import tempfile
print('Building a filename with PID:')
filename = '/tmp/guess_my_name.{}.txt'.format(os.getpid())
with open(filename, 'w+b') as temp:
print('temp:')
print(' {!r}'.format(temp))
print('temp.name:')
print(' {!r}'.format(temp.name))
# Clean up the temporary file yourself.
os.remove(filename)
print()
print('TemporaryFile:')
with tempfile.TemporaryFile() as temp:
print('temp:')
print(' {!r}'.format(temp))
print('temp.name:')
print(' {!r}'.format(temp.name))
# Automatically cleans up the file.
Este ejemplo ilustra la diferencia en la creación de un archivo temporal usando
un patrón común para crear un nombre, en lugar de usar la función
TemporaryFile()
. El archivo devuelto por TemporaryFile()
no tiene
nombre.
$ python3 tempfile_TemporaryFile.py
Building a filename with PID:
temp:
<_io.BufferedRandom name='/tmp/guess_my_name.12151.txt'>
temp.name:
'/tmp/guess_my_name.12151.txt'
TemporaryFile:
temp:
<_io.BufferedRandom name=4>
temp.name:
4
De forma predeterminada, el identificador de archivo se crea con el modo
'w+b'
por lo que se comporta de manera consistente en todas las plataformas
y la persona que llama puede escribir y leer de él.
import os
import tempfile
with tempfile.TemporaryFile() as temp:
temp.write(b'Some data')
temp.seek(0)
print(temp.read())
Después de escribir, el identificador de archivo debe ser «rebobinado» usando
seek()
con el fin de leer los datos de nuevo.
$ python3 tempfile_TemporaryFile_binary.py
b'Some data'
Para abrir el archivo en modo de texto, configura mode
con 'w+t'
cuando
el archivo es creado.
import tempfile
with tempfile.TemporaryFile(mode='w+t') as f:
f.writelines(['first\n', 'second\n'])
f.seek(0)
for line in f:
print(line.rstrip())
El identificador de archivo trata los datos como texto.
$ python3 tempfile_TemporaryFile_text.py
first
second
Archivos con nombre¶
Hay situaciones donde tener un archivo temporal con nombre es importante. Para
aplicaciones que abarcan múltiples procesos, o incluso hosts, nombrar el
archivo es la forma más sencilla de pasarlo entre partes de la aplicación. La
función NamedTemporaryFile()
crea un archivo sin desvincularlo, por lo que
conserva su nombre (se accede con el atributo name
).
import os
import pathlib
import tempfile
with tempfile.NamedTemporaryFile() as temp:
print('temp:')
print(' {!r}'.format(temp))
print('temp.name:')
print(' {!r}'.format(temp.name))
f = pathlib.Path(temp.name)
print('Exists after close:', f.exists())
El archivo se elimina después de cerrar el identificador.
$ python3 tempfile_NamedTemporaryFile.py
temp:
<tempfile._TemporaryFileWrapper object at 0x1011b2d30>
temp.name:
'/var/folders/5q/8gk0wq888xlggz008k8dr7180000hg/T/tmps4qh5zde'
Exists after close: False
Archivos en spool¶
Para archivos temporales que contienen cantidades relativamente pequeñas de
datos, probablemente sea más eficiente usar un SpooledTemporaryFile
porque
guarda el contenido del archivo en la memoria usando un buffer io.BytesIO
o
io.StringIO
hasta que alcancen un umbral de tamaño . Cuando la cantidad de
datos pasa el umbral, se «enrolla» y se escribe al disco, y luego el buffer se
sustituye por un TemporaryFile
normal.
import tempfile
with tempfile.SpooledTemporaryFile(max_size=100,
mode='w+t',
encoding='utf-8') as temp:
print('temp: {!r}'.format(temp))
for i in range(3):
temp.write('This line is repeated over and over.\n')
print(temp._rolled, temp._file)
Este ejemplo usa atributos privados del SpooledTemporaryFile
para
determinar cuándo ha ocurrido la transferencia al disco. Normalmente no es
necesario comprobar este estado, excepto cuando se ajusta el tamaño del buffer.
$ python3 tempfile_SpooledTemporaryFile.py
temp: <tempfile.SpooledTemporaryFile object at 0x1007b2c88>
False <_io.StringIO object at 0x1007a3d38>
False <_io.StringIO object at 0x1007a3d38>
True <_io.TextIOWrapper name=4 mode='w+t' encoding='utf-8'>
Para hacer que el buffer se escriba explícitamente en el disco, llama a los
métodos rollover()
o fileno()
.
import tempfile
with tempfile.SpooledTemporaryFile(max_size=1000,
mode='w+t',
encoding='utf-8') as temp:
print('temp: {!r}'.format(temp))
for i in range(3):
temp.write('This line is repeated over and over.\n')
print(temp._rolled, temp._file)
print('rolling over')
temp.rollover()
print(temp._rolled, temp._file)
En este ejemplo, debido a que el tamaño del buffer es mucho más grande que la
cantidad de datos, no se crearía ningún archivo en el disco excepto que
rollover()
sea llamado.
$ python3 tempfile_SpooledTemporaryFile_explicit.py
temp: <tempfile.SpooledTemporaryFile object at 0x1007b2c88>
False <_io.StringIO object at 0x1007a3d38>
False <_io.StringIO object at 0x1007a3d38>
False <_io.StringIO object at 0x1007a3d38>
rolling over
True <_io.TextIOWrapper name=4 mode='w+t' encoding='utf-8'>
Directorios temporales¶
Cuando se necesitan varios archivos temporales, puede ser más conveniente crear
un directorio temporal con TemporaryDirectory
y abrir todos los archivos en
ese directorio.
import pathlib
import tempfile
with tempfile.TemporaryDirectory() as directory_name:
the_dir = pathlib.Path(directory_name)
print(the_dir)
a_file = the_dir / 'a_file.txt'
a_file.write_text('This file is deleted.')
print('Directory exists after?', the_dir.exists())
print('Contents after:', list(the_dir.glob('*')))
El gestor de contexto produce el nombre del directorio, que luego puede ser utilizado dentro del bloque de contexto para construir otros nombres de archivo.
$ python3 tempfile_TemporaryDirectory.py
/var/folders/5q/8gk0wq888xlggz008k8dr7180000hg/T/tmp_urhiioj
Directory exists after? False
Contents after: []
Predicción de nombres¶
Aunque es menos seguro que los archivos temporales estrictamente anónimos, incluir una parte predecible en el nombre hace posible encontrar el archivo y examinarlo para fines de depuración. Todas las funciones descritas hasta ahora toman tres argumentos para controlar los nombres de archivo hasta cierto punto. Los nombres se generan utilizando la fórmula:
dir + prefix + random + suffix
Todos los valores, excepto random
, pueden pasarse como argumentos a las
funciones para la creación de archivos o directorios temporales.
import tempfile
with tempfile.NamedTemporaryFile(suffix='_suffix',
prefix='prefix_',
dir='/tmp') as temp:
print('temp:')
print(' ', temp)
print('temp.name:')
print(' ', temp.name)
Los argumentos prefix
y suffix
se combinan con una cadena aleatoria de
caracteres para construir el nombre de archivo, y se toma el argumento dir
tal como está y se utiliza como la ubicación del nuevo archivo.
$ python3 tempfile_NamedTemporaryFile_args.py
temp:
<tempfile._TemporaryFileWrapper object at 0x1018b2d68>
temp.name:
/tmp/prefix_q6wd5czl_suffix
Ubicación de archivos temporales¶
Si no se da un destino explícito usando el argumento dir
, la ruta utilizada
para los archivos temporales variará según la versión actual y los ajustes de
plataforma. El módulo tempfile
incluye dos funciones para consultar la
configuración que se utiliza en tiempo de ejecución.
import tempfile
print('gettempdir():', tempfile.gettempdir())
print('gettempprefix():', tempfile.gettempprefix())
gettempdir()
devuelve el directorio predeterminado que contendrá todos los
archivos temporales y gettempprefix()
devuelve la cadena prefijo para
nuevos nombres de archivos y directorios.
$ python3 tempfile_settings.py
gettempdir(): /var/folders/5q/8gk0wq888xlggz008k8dr7180000hg/T
gettempprefix(): tmp
El valor devuelto por gettempdir()
se establece en función del algoritmo
directo de buscar en una lista de ubicaciones el primer lugar donde el proceso
actual puede crear un archivo. La lista de búsqueda es:
- La variable de entorno
TMPDIR
- La variable de entorno
TEMP
- La variable de entorno
TMP
- Una alternativa, basada en la plataforma. (Windows usa la primera disponible
entre
C:\temp
,C:\tmp
,\temp
, o\tmp
. Otras plataformas usan/tmp
,/var/tmp
, o/usr/tmp
.) - Si no se puede encontrar otro directorio, se utiliza el directorio de trabajo actual.
import tempfile
tempfile.tempdir = '/I/changed/this/path'
print('gettempdir():', tempfile.gettempdir())
Programas que necesitan usar una ubicación global para todos los archivos
temporales sin utilizar ninguna de estas variables de entorno deben establecer
tempfile.tempdir
directamente asignando un valor a la variable.
$ python3 tempfile_tempdir.py
gettempdir(): /I/changed/this/path
Ver también
- Documentación de la biblioteca estándar para tempfile
random
– Generadores de números pseudoaleatorios, usados para introducir valores aleatorios en nombres de archivos temporales