Générer des noms de fichiers temporaires sans créer de fichier réel en Python

98

La question, numéro 10501247 , dans stackoverflow donne la réponse comment créer un fichier temporaire en Python.
Je n'ai besoin que d'un nom de fichier temporaire dans mon cas.
L'appel de tempfile.NamedTemporaryFile () renvoie le descripteur de fichier après la création réelle du fichier.
Existe-t-il un moyen d'obtenir uniquement le nom du fichier?

# 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')
...
Colline
la source
7
NamedTemporaryFilegarantit un nom unique, (probablement) en l'essayant et en réessayant s'il existe. Obtenir juste un nom ne garantira pas que vous pourrez créer le fichier plus tard, vous vous ouvrez à la condition de concurrence de quelqu'un d'autre utilisant le même nom avant vous.
Joachim Isaksson
5
@Joachim C'est vrai, il y a une condition de concurrence ici et il serait préférable d'éviter cela. Cependant, vous devez parfois passer un nom de fichier temporaire à une fonction (ouverture du fichier en interne). Avoir un nom bien aléatoire donne une bien meilleure probabilité que la condition de concurrence ne soit pas un problème. Je pense qu'il est nécessaire de fournir un bon nom de fichier temporaire pour minimiser le risque d'échec d'une condition de concurrence. Bien sûr, l'ajout d'un bon préfixe et d'un suffixe en fonction du processus en cours et de la tâche en cours d'exécution réduira encore les risques de collision.
PolyMesh
@PolyMesh Vous pouvez éviter la condition de concurrence en créant un répertoire temporaire puis en utilisant un fichier de nom fixe à l'intérieur. Ainsi, votre fonction accepte un répertoire, plutôt qu'un fichier, et crée toujours le même fichier.
DylanYoung
utilisez tarfile et passez-le le fileobj
Wyrmwood

Réponses:

67

Si vous voulez uniquement un nom de fichier temporaire, vous pouvez appeler la fonction de fichier temporaire interne _get_candidate_names():

import tempfile

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

Appeler à nextnouveau, renverra un autre nom, etc. Cela ne vous donne pas le chemin du dossier temporaire. Pour obtenir le répertoire 'tmp' par défaut, utilisez:

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp 
Marcin
la source
3
la meilleure façon de créer un répertoire temporaire est de temp_dir = tempfile.mkdtemp(prefix='some-prefix_')créer en toute sécurité un répertoire temporaire et de renvoyer une chaîne avec le chemin absolu.
Emanuel Ey
3
Il est important de souligner que next(tempfile._get_candidate_names())ne renvoie pas nécessairement un chemin inexistant, c'est pourquoi les interfaces de fichier temporaire au niveau de l'utilisateur peuvent essayer plusieurs noms jusqu'à ce qu'un nom inutilisé soit trouvé :
Eli Korvigo
1
On pourrait utiliser public tempfile.gettempdir()au lieu de privé tempfile._get_default_tempdir().
flonk
@EmanuelEy Il est important de se souvenir lors de tempfile.mkdtempl'utilisation que l'utilisateur est responsable de la suppression du répertoire temporaire et de son contenu une fois terminé.
Daniel Braun
46

Je pense que le moyen le plus simple et le plus sûr de le faire est quelque chose comme:

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

Un répertoire temporaire est créé auquel vous seul pouvez accéder, il ne devrait donc y avoir aucun problème de sécurité, mais aucun fichier ne sera créé, vous pouvez donc simplement choisir le nom de fichier que vous souhaitez créer dans ce répertoire.

edit: Dans Python 3, vous pouvez maintenant utiliser tempfile.TemporaryDirectory()comme gestionnaire de contexte pour gérer la suppression à votre place:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path
Alec
la source
1
Comme Daniel Braun l'a mentionné ci-dessus: Il est important de se souvenir lors de tempfile.mkdtempl'utilisation que l'utilisateur est responsable de la suppression du répertoire temporaire et de son contenu une fois terminé.
bitinerant
4
Si vous utilisez tempfile.TemporaryDirectory()comme gestionnaire de contexte, il sera supprimé pour vous.
gerrit
17

Il est peut-être un peu tard, mais y a-t-il quelque chose de mal à cela?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
    temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')
Russell
la source
37
Ce code créera en fait le fichier temporaire afin d'obtenir son nom, alors que dans la question il le dit without creating actual file in Python.
Jakub Kukul
Cela ne répond pas à la question
herve
8

tempfile.mktemp() fais ça.

Mais notez qu'il est obsolète. Cependant, il ne créera pas le fichier et il s'agit d'une fonction publique dans tempfile par rapport à l'utilisation de _get_candidate_names().

La raison pour laquelle il est obsolète est due à l'intervalle de temps entre l'appel et la tentative de création du fichier. Cependant, dans mon cas, les chances que cela se produise sont si minces et même si cela échouait, ce serait acceptable. Mais c'est à vous d'évaluer votre cas d'utilisation.

Zitrax
la source
1
«Même si cela échouait, ce serait acceptable»; la condition de concurrence n'est pas simplement un risque d'échec, c'est un risque de sécurité (voir la tempfile.mktempdocumentation). Cela ne devrait donc pas être considéré comme acceptable.
bignose
4
@bignose C'est un problème de sécurité potentiel . Cela dépend de ce que vous voulez faire, de l'environnement d'exécution dans lequel vous vous trouvez, etc. Cela dit: il peut être plus sûr de faire quelque chose comme os.path.join(tempfile.mkdtemp(), 'something')Là au moins le répertoire est créé (et vous appartient, je suppose).
Alec
5

En combinant les réponses précédentes, ma solution est:

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

Rendre some_idfacultatif s'il n'est pas nécessaire pour vous.

juanmirocks
la source
Encore une fois, les noms des candidats pourraient ne pas être réellement disponibles. C'est la bonne réponse: stackoverflow.com/a/45803022/6387880
j4hangir
1
Cependant, il est probable qu'il faille créer des noms aléatoires. Néanmoins, pour être sûr, s'il _get_candidate_names()n'existe pas, on peut utiliser par défaut un générateur de chaînes semi-aléatoire. Par exemple, certains uuid.
juanmirocks
4

Comme Joachim Isaksson l'a dit dans les commentaires, si vous n'obtenez qu'un nom, vous pouvez avoir des problèmes si un autre programme utilise ce nom avant votre programme. Les chances sont minces, mais pas impossibles.

Donc, la chose sûre à faire dans cette situation est d'utiliser le constructeur complet GzipFile (), qui a la signature GzipFile( [filename[, mode[, compresslevel[, fileobj]]]]). Vous pouvez donc lui transmettre le fichier obj ouvert, ainsi qu'un nom de fichier, si vous le souhaitez. Consultez la documentation gzip pour plus de détails.

PM 2Bague
la source