2012-01-05 12 views
11

Ho bisogno di aggiornare un file. L'ho letto e lo ho scritto con le modifiche. Tuttavia, preferirei scrivere su un file temporaneo e rinominarlo in posizione.In python, creare un tempfile nella stessa directory di un altro file?

temp = tempfile.NamedTemporaryFile() 
tempname = temp.name 
temp.write(new_data) 
temp.close() 
os.rename(tempname, data_file_name) 

Il problema è che tempfile.NamedTemporaryFile() rende il file temporaneo nella /tmp che è un file system diverso. Ciò significa che os.rename() non riesce. Se uso shlib.move() invece poi non ho l'aggiornamento atomica che "mv" prevede (per i file nello stesso file system, bla, bla, ecc)

So tempfile.NamedTemporaryFile() prende un parametro "dir", ma data_file_name potrebbe essere "foo.txt" nel qual caso dir = '.'; o data_file_name potrebbe essere "/path/to/the/data/foo.txt" nel qual caso dir = "/path/to/the/data".

Quello che mi piacerebbe davvero è che il file temp sia data_file_name + "alcuni dati casuali". Ciò avrebbe il vantaggio di fallire in un modo che lascerebbe indizi utili.

Suggerimenti?

+3

Perché si sta utilizzando un file temporaneo in primo luogo, se non si desidera che venga inserito nella directory per i file temporanei? Cosa non va contro l'utilizzo di file ordinari? –

+1

David: Voglio usare un file temporaneo perché voglio che l'aggiornamento sia atomico (o atomico come uno può essere con os.rename()). Cioè, se il file system si riempie o c'è qualche altro problema, non voglio che il file sia scritto a metà. – TomOnTime

+0

Bene, questo potrebbe essere difficile da raggiungere, poiché non si sa mai veramente, se i file scritti in una cartella diversa si trovano sullo stesso file system della directory locale. Vedo il vantaggio di organizzare il tuo output in una sorta di commit. Per essere relativamente sicuro che questo è il caso, probabilmente gestirò la mia directory temporanea - anche se poi ti occuperesti anche della pulizia di questa cartella. –

risposta

17

È possibile utilizzare:

  • prefix per rendere il file temporaneo iniziano con lo stesso nome del file originale .
  • dir per specificare dove posizionare il file temporaneo.
  • os.path.split per dividere la directory dal nome file.

import tempfile 
import os 
dirname, basename = os.path.split(filename) 
temp = tempfile.NamedTemporaryFile(prefix=basename, dir=dirname) 
print(temp.name) 
+0

Se filename = 'foo' allora dirname sarà ''. Sono piacevolmente sorpreso dal fatto che NamedTemporaryFile funzioni con dir = '' come dir = None. Grazie! – TomOnTime

+0

Giusto per rendere esplicito questo: devi anche passare 'delete = False' al costruttore NamedTemporaryFile, altrimenti il ​​file verrà eliminato alla chiusura. – moeffju

2

Io uso l'ora attuale come "alcuni dati casuali" aggiunti a una stringa di base per un nome di file temporaneo unico:

import time 

temp_file_name = data_file_name + str(time.time()) 
+0

Questo è allettante, ma ho visto abbastanza problemi di sicurezza da parte delle persone che eseguono il loro file system temporaneo che so usare quello fornito da tempfile. – TomOnTime

+0

Proprio come una nota aggiunta qui, alcuni anni dopo, questo avrà dei conflitti se questo viene eseguito due volte nello stesso millisecondo, cosa che è sicuramente possibile nei casi d'uso della maggior parte delle persone. È meglio usare l'implementazione ufficiale di tempfile, cose del genere e condizioni di gara quando cerchi di evitarlo. – daboross

4

È possibile passare un percorso di file nel parametro del costruttore 'dir'. Funziona, come desideri.

>>> t = tempfile.NamedTemporaryFile(dir="/Users/rafal") 
>>> t.name 
'/Users/rafal/tmplo45Js' 

Fonte: http://docs.python.org/library/tempfile.html#tempfile.NamedTemporaryFile

+2

info: senza 'delete = False' il file viene cancellato non appena il gestore di file viene chiuso. – gecco

+0

Questo presuppone che sappiamo qual è il dir. – TomOnTime

+0

Lo sappiamo. La domanda dell'OP contiene già la suddivisione di un percorso in dir e nome file, quindi è ridondante scrivere qui. –

4

Per soddisfare tutte le vostre lista di controllo penso che ci si vuole utilizzare ...

temp = tempfile.NamedTemporaryFile(prefix=data_file_name, dir=path, 
            delete=False) 

importante avere il delete=False, perché altrimenti:

[...] Se delete è true (il valore predefinito), il file viene eliminato non appena è chiuso.

+0

Questo presuppone che sappiamo qual è il percorso. – TomOnTime

-1

Il modulo tempfile che si utilizza fornisce un modo sicuro di gestione dei file temporanei. Se si vuole veramente utilizzare il proprio sistema, si dovrebbe essere consapevoli che potrebbe essere vulnerabile agli attacchi (in particolare gli attacchi symlink).

Un modo semplice per generare un nome di file unico temporaneo (anche se un nome piuttosto lungo) è:

import uuid 
import os 

tempfilename = 'myprefix-%s.dat' % str(uuid.uuid4()) 

with open(tempfilename, 'rw') as tempfile: 
    # do stuff 

os.remove(tempfilename) 

Ma questo è un po 'hacker; considerare piuttosto piuttosto l'utilizzo del modulo tempfile con i parametri corretti prefix e dir passati a NamedTemporaryFile, come descritto nelle altre risposte.

+0

Questo è allettante, ma ho visto abbastanza problemi di sicurezza causati da persone che eseguono il loro file system temporaneo che so usare quello fornito da tempfile. – TomOnTime

+0

Assolutamente, usare qualcosa del genere è una cattiva idea nel codice di produzione. In un ambiente in cui questo non è un problema (ad esempio la registrazione dei dati di simulazione), 'uuid' presenta un modo per generare una stringa casuale unica. –

Problemi correlati