Genere nombres de archivos temporales sin crear un archivo real en Python

98

La pregunta, número 10501247 , en stackoverflow da respuesta a cómo crear un archivo temporal en Python.
Solo necesito tener un nombre de archivo temporal en mi caso.
Llamar a tempfile.NamedTemporaryFile () devuelve el identificador de archivo después de la creación del archivo real.
¿Hay forma de obtener solo el nombre del archivo?

# Trying to get temp file path
tf = tempfile.NamedTemporaryFile()
temp_file_name = tf.name
tf.close()
# Here is my real purpose to get the temp_file_name
f = gzip.open(temp_file_name ,'wb')
...
colina
fuente
7
NamedTemporaryFilegarantiza un nombre único, (probablemente) probándolo y volviendo a intentarlo si existe. Obtener solo un nombre no garantizará que realmente pueda crear el archivo más tarde, se está abriendo a la condición de carrera de otra persona que usa el mismo nombre antes que usted.
Joachim Isaksson
5
@Joachim Es cierto, aquí hay una condición de carrera y sería preferible evitarla. Sin embargo, a veces tienes que pasar un nombre de archivo temporal a una función (el archivo se abre internamente). Tener un nombre aleatorio proporciona una probabilidad mucho mayor de que la condición de carrera no sea un problema. Creo que existe una necesidad válida de proporcionar un buen nombre de archivo temporal para minimizar la posibilidad de una falla en la condición de carrera. Por supuesto, agregar un buen prefijo y sufijo según el proceso en ejecución y la tarea que se está realizando proporcionará incluso menos posibilidades de colisión.
PolyMesh
@PolyMesh Puede evitar la condición de carrera creando un directorio temporal y luego usando un archivo de nombre fijo dentro de él. Entonces, su función acepta un directorio, en lugar de un archivo, y siempre crea el mismo archivo.
DylanYoung
use tarfile y páselo al fileobj
Wyrmwood

Respuestas:

67

Si solo desea un nombre de archivo temporal, puede llamar a la función interna de archivo temporal _get_candidate_names():

import tempfile

temp_name = next(tempfile._get_candidate_names())
% e.g. px9cp65s

Llamar de nextnuevo, devolverá otro nombre, etc. Esto no le da la ruta a la carpeta temporal. Para obtener el directorio 'tmp' predeterminado, use:

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp 
Marcin
fuente
3
La mejor manera de crear un directorio temporal es temp_dir = tempfile.mkdtemp(prefix='some-prefix_')crear de forma segura un directorio temporal y devolver una cadena con la ruta absoluta.
Emanuel Ey
3
Es importante señalar que next(tempfile._get_candidate_names())no necesariamente devuelve una ruta inexistente, es por eso que las interfaces de archivos temporales a nivel de usuario pueden probar varios nombres hasta que se encuentre uno sin usar :
Eli Korvigo
1
Se podría usar público en tempfile.gettempdir()lugar de privado tempfile._get_default_tempdir().
flonk
@EmanuelEy Es importante recordar cuando tempfile.mkdtempel usuario es el responsable de eliminar el directorio temporal y su contenido cuando termina con él.
Daniel Braun
46

Creo que la forma más fácil y segura de hacer esto es algo como:

path = os.path.join(tempfile.mkdtemp(), 'something')

Se crea un directorio temporal al que solo usted puede acceder, por lo que no debería haber problemas de seguridad, pero no se crearán archivos en él, por lo que puede elegir cualquier nombre de archivo que desee crear en ese directorio.

editar: en Python 3 ahora puede usarlo tempfile.TemporaryDirectory()como administrador de contexto para manejar la eliminación por usted:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path
Alec
fuente
1
Como mencionó Daniel Braun anteriormente: Es importante recordar cuando tempfile.mkdtempel usuario es responsable de eliminar el directorio temporal y su contenido cuando termina con él.
bitinerante
4
Si lo usa tempfile.TemporaryDirectory()como administrador de contexto, se eliminará.
Gerrit
17

Puede que sea un poco tarde, pero ¿hay algo de malo en esto?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
    temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')
Russell
fuente
37
Este código realmente creará el archivo temporal para obtener su nombre, mientras que en la pregunta dice without creating actual file in Python.
Jakub Kukul
Esto no responde a la pregunta
herve
8

tempfile.mktemp() hacer esto.

Pero tenga en cuenta que está en desuso. Sin embargo, no creará el archivo y es una función pública en tempfile en comparación con el uso de _get_candidate_names().

La razón por la que está en desuso se debe a la brecha de tiempo entre llamar a esto y realmente intentar crear el archivo. Sin embargo, en mi caso, la posibilidad de eso es muy pequeña e incluso si fallara, sería aceptable. Pero depende de usted evaluar su caso de uso.

Zitrax
fuente
1
“Incluso si fracasara sería aceptable”; la condición de carrera no es simplemente un riesgo de falla, es un riesgo de seguridad (consulte la tempfile.mktempdocumentación). Entonces eso no debería considerarse aceptable.
bignose
4
@bignose Es un problema de seguridad potencial . Depende de lo que quieras hacer, el entorno de ejecución en el que te encuentres, etc. Dicho esto: puede ser más seguro hacer algo como os.path.join(tempfile.mkdtemp(), 'something')Allí, al menos, se crea el directorio (y es de tu propiedad, supongo).
Alec
5

Combinando las respuestas anteriores, mi solución es:

def get_tempfile_name(some_id):
    return os.path.join(tempfile.gettempdir(), next(tempfile._get_candidate_names()) + "_" + some_id)

Haga some_idopcional si no es necesario para usted.

juanmirocks
fuente
Nuevamente, es posible que los nombres de los candidatos no estén realmente disponibles. Esta es la respuesta correcta: stackoverflow.com/a/45803022/6387880
j4hangir
1
Sin embargo, es probable que uno necesite crear nombres aleatorios. No obstante, para estar seguro, si _get_candidate_names()no existe, se puede utilizar por defecto algún generador de cadenas semi-aleatorio. Por ejemplo, algunos uuid.
juanmirocks
4

Como dijo Joachim Isaksson en los comentarios, si solo obtiene un nombre, puede tener problemas si algún otro programa usa ese nombre antes que su programa. Las posibilidades son escasas, pero no imposibles.

Entonces, lo más seguro en esta situación es usar el constructor GzipFile () completo, que tiene la firma GzipFile( [filename[, mode[, compresslevel[, fileobj]]]]). Entonces puede pasarle el fileobj abierto, y también un nombre de archivo, si lo desea. Consulte los documentos de gzip para obtener más detalles.

PM 2 Anillo
fuente