Genera nomi di file temporanei senza creare file effettivi in ​​Python


98

La domanda, numero 10501247 , in stackoverflow fornisce la risposta su come creare un file temporaneo in Python.
Ho solo bisogno di avere il nome del file temporaneo nel mio caso.
La chiamata tempfile.NamedTemporaryFile () restituisce l'handle di file dopo la creazione effettiva del file.
C'è un modo per ottenere solo il nome del file?

# 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')
...

7
NamedTemporaryFilegarantisce un nome univoco, (probabilmente) provandolo e riprovando se esiste. Ottenere solo un nome non garantisce che puoi effettivamente creare il file in seguito, ti stai aprendo alla condizione di gara di qualcun altro che usa lo stesso nome prima di te.
Joachim Isaksson

5
@Joachim Vero, qui c'è una condizione di gara e sarebbe preferibile evitarlo. Tuttavia, a volte è necessario passare un nome di file temporaneo a una funzione (l'apertura del file avviene internamente.) Avere un nome abbastanza casuale dà una probabilità molto migliore che la condizione di competizione non sia un problema. Penso che ci sia una valida necessità di fornire un buon nome di file temporaneo per ridurre al minimo la possibilità di un errore della condizione di competizione. Ovviamente l'aggiunta di un buon prefisso e suffisso in base al processo in esecuzione e all'attività svolta fornirà ancora meno possibilità di collisione.
PolyMesh

@PolyMesh È possibile evitare la condizione di competizione creando una directory temporanea e quindi utilizzando un file a nome fisso al suo interno. Quindi la tua funzione accetta una directory, piuttosto che un file, e crea sempre lo stesso file.
DylanYoung

usa tarfile e passagli il fileobj
Wyrmwood

Risposte:


67

Se vuoi solo un nome di file temporaneo puoi chiamare la funzione del file temporaneo interno _get_candidate_names():

import tempfile

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

Chiamando di nextnuovo, verrà restituito un altro nome, ecc. Ciò non fornisce il percorso della cartella temporanea. Per ottenere la directory "tmp" predefinita, utilizza:

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp 

3
Il modo migliore per creare una directory temporanea è temp_dir = tempfile.mkdtemp(prefix='some-prefix_')che creerà in modo sicuro una directory temporanea e restituirà una stringa con il percorso assoluto.
Emanuel Ey

3
È importante sottolineare che next(tempfile._get_candidate_names())non restituisce necessariamente un percorso inesistente, ecco perché le interfacce dei file temporanei a livello utente possono provare diversi nomi finché non ne viene trovato uno inutilizzato :
Eli Korvigo

1
Si potrebbe usare pubblico tempfile.gettempdir()anziché privato tempfile._get_default_tempdir().
flonk

@EmanuelEy È importante ricordare che quando si utilizza tempfile.mkdtempl'utente è responsabile dell'eliminazione della directory temporanea e del suo contenuto una volta terminato.
Daniel Braun

46

Penso che il modo più semplice e sicuro per farlo sia qualcosa del tipo:

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

Viene creata una directory temporanea a cui solo tu puoi accedere, quindi non dovrebbero esserci problemi di sicurezza, ma non ci saranno file creati al suo interno, quindi puoi semplicemente scegliere qualsiasi nome di file che desideri creare in quella directory.

modifica: in Python 3 ora puoi utilizzare tempfile.TemporaryDirectory()come gestore di contesto per gestire l'eliminazione per te:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path

1
Come menzionato sopra da Daniel Braun: è importante ricordare che quando si usa tempfile.mkdtempl'utente è responsabile dell'eliminazione della directory temporanea e del suo contenuto quando ha finito con essa.
bitinerant

4
Se utilizzi tempfile.TemporaryDirectory()come gestore di contesto, verrà eliminato per te.
gerrit

17

Potrebbe essere un po 'tardi, ma c'è qualcosa di sbagliato in questo?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
    temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')

37
Questo codice creerà effettivamente il file temporaneo per ottenere il suo nome, mentre nella domanda dice without creating actual file in Python.
Jakub Kukul

Questo non risponde alla domanda
Herve

8

tempfile.mktemp() Fai questo.

Ma nota che è deprecato. Tuttavia non creerà il file ed è una funzione pubblica in tempfile rispetto all'utilizzo di _get_candidate_names().

Il motivo per cui è deprecato è dovuto all'intervallo di tempo tra la chiamata e il tentativo effettivo di creare il file. Tuttavia nel mio caso la possibilità che ciò avvenga è così esigua e anche se fallisse sarebbe accettabile. Ma sta a te valutare il tuo caso d'uso.


1
"Anche se fallisse, sarebbe accettabile"; la race condition non è solo un rischio di fallimento, è un rischio per la sicurezza (vedere la tempfile.mktempdocumentazione). Quindi non dovrebbe essere considerato accettabile.
bignose

4
@ bignose È un potenziale problema di sicurezza. Dipende da cosa si vuole fare, dall'ambiente di esecuzione in cui ci si trova, ecc. Detto questo: potrebbe essere più sicuro fare qualcosa come os.path.join(tempfile.mkdtemp(), 'something')Là almeno la directory è stata creata (e di vostra proprietà, presumo).
Alec

5

Combinando le risposte precedenti, la mia soluzione è:

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

Rendi some_idfacoltativo se non necessario per te.


Anche in questo caso, i nomi dei candidati potrebbero non essere effettivamente disponibili. Questa è la risposta corretta: stackoverflow.com/a/45803022/6387880
j4hangir

1
Tuttavia, probabilmente è necessario creare nomi casuali. Tuttavia, per essere sicuri, se _get_candidate_names()non esiste, si può impostare di default un generatore di stringhe semi-casuale. Ad esempio alcuni uuid.
juanmirocks

4

Come ha detto Joachim Isaksson nei commenti, se ottieni solo un nome potresti avere problemi se qualche altro programma utilizza quel nome prima del tuo programma. Le possibilità sono scarse, ma non impossibili.

Quindi la cosa sicura da fare in questa situazione è usare il costruttore completo GzipFile (), che ha la firma GzipFile( [filename[, mode[, compresslevel[, fileobj]]]]). Quindi puoi passargli il fileobj aperto e anche un nome di file, se lo desideri. Vedere i documenti gzip per i dettagli.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.