tempfile - Oggetti Temporanei di File System
Scopo: Crea oggetti di file system temporanei
Creare in sicurezza file temporanei con nomi univoci, in modo che nessuno possa identificarli nel tentativo di forzare una applicazione o catturarne i dati è impegnativo. Il modulo tempfile fornisce parecchie funzioni per creare risorse temporanee di file system in sicurezza. TemporaryFile()
apre e restituisce un file senza nome, NamedTemporaryFile()
apre e restituisce un file con un nome, SpooledTemporaryFile
mantiene il suo contenuto in memoria prima di scriverlo su disco e TemporaryDirectory()
è un gestore di contesto che elimina la directory quanto il contesto viene chiuso.
File Temporanei
Applicazioni che necessitano di file temporanei per conservare dati, senza condividere quel file con altri programmi, dovrebbero usare la funzione TemporaryFile()
per creare i file. Essa crea un file e, nelle piattaforme in cui è possibile, esegue immediatamente un operazione di unlink. Questo rende impossibile a un altro programma il trovare o aprire il file, visto che non esiste nessun riferimento a esso nella tabella del file system. Il file creato da TemporaryFile()
viene eliminato automaticamente quando viene chiuso, sia che lo si faccia chiamando close()
oppure utilizzando l'API del gestore di contesto con l'istruzione with
.
# tempfile_TemporaryFile.py
import os
import tempfile
print('Creazione di un nome di file con PID:')
filename = '/tmp/indovina_il_nome.{}.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('File Temporaraneo:')
with tempfile.TemporaryFile() as temp:
print('temp:')
print(' {!r}'.format(temp))
print('temp.name:')
print(' {!r}'.format(temp.name))
# Elimina il file automaticamente
Questo esempio illustra la differenza tra il creare un file temporaneo usando una operatività comune per impostarne il nome, e l'usare la funzione TemporaryFile()
. Il file restituito da TemporaryFile non ha un nome.
$ python3 tempfile_TemporaryFile.py Creazione di un nome di file con PID: temp: <_io.BufferedRandom name='/tmp/indovina_il_nome.16226.txt'> temp.name: '/tmp/indovina_il_nome.16226.txt' File Temporaraneo: temp: <_io.BufferedRandom name=3> temp.name: 3
In modalità predefinita, l'handle del file viene creato con modalità 'w+b'
, in modo che si comporti consistentemente su tutte le piattaforme e il chiamante può scrivere o leggere da esso.
import os
import tempfile
temp = tempfile.TemporaryFile()
try:
temp.write('Qualche dato')
temp.seek(0)
print temp.read()
finally:
temp.close()
Nella modalità predefinita, l'handle del file viene creato nella modalità 'w+b'
in modo da comportarsi in modo consistente su tutte le piattaforme e il chiamante può da esso scrivere e leggere.
# tempfile_TemporaryFile_binary.py
import os
import tempfile
with tempfile.TemporaryFile() as temp:
temp.write(b'Qualche dato')
temp.seek(0)
print(temp.read())
Dopo la scrittura si deve "riavvolgere" l'handle del file usando seek()
per potere leggere di nuovo i dati da esso.
$ python3 tempfile_TemporaryFile_binary.py b'Qualche dato'
Per aprire il file in formato testo, si passa mode='w+t'
quando lo si crea:
# tempfile_TemporaryFile_text.py
import tempfile
with tempfile.TemporaryFile(mode='w+t') as f:
f.writelines(['primo\n', 'secondo\n'])
f.seek(0)
for line in f:
print(line.rstrip())
L'handle del file considera i dati come testo:
$ python3 tempfile_TemporaryFile_text.py primo secondo
File Nominati
Ci sono situazioni nelle quali avere un file temporaneo con un nome è importante. Se una applicazione sviluppa processi multipli, o anche host, nominare il file diventa il modo più semplice per passarlo tra le parti dell'applicazione. La funzione NamedTemporaryFile()
crea un file senza toglierne il collegamento, in modo che esso conservi il suo nome, al quale si accede con l'attributo name.
# tempfile_NamedTemporaryFile.py
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('Esiste dopo la chiusura:', f.exists())
Il file viene rimosso dopo che l'handle viene chiuso.
$ python3 tempfile_NamedTemporaryFile.py temp: <tempfile._TemporaryFileWrapper object at 0x7f642f22aa58> temp.name: '/tmp/tmpdvrok0ji' Esiste dopo la chiusura: False
File in Memoria
Per file temporanei che contengono una limitata mole di dati, è probabilmente più efficace l'utilizzo di SpooledTemporaryFile
in quanto il contenuto del file viene trattenuto in memoria tramite un buffer io.BytesIO
oppure io.StringIO
fino a che viene raggiunta una dimensione soglia. Quando i dati superano questa soglia, vengono scritti su disco e il buffer viene sostituito da un normale TemporaryFile()
.
# tempfile_SpooledTemporaryFile.py
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('Questa riga viene ripetuta ad libitum.\n')
print(temp._rolled, temp._file)
Questo esempio utilizza gli attributi privati di SpooledTemporaryFile
per determinare quando il riversamento (rollover) su disco accade. Questo non è normalmente necessario per verificare lo stato a meno che non si stia aggiustando la dimensione del buffer.
$ python3 tempfile_SpooledTemporaryFile.py temp: <tempfile.SpooledTemporaryFile object at 0x7f7a5f738a20> False <_io.StringIO object at 0x7f7a5f782708> False <_io.StringIO object at 0x7f7a5f782708> True <_io.TextIOWrapper name=3 mode='w+t' encoding='utf-8'>
Per provocare una esplicita scrittura del buffer su disco, si invocano i metodi rollover()
oppure fileno()
.
# tempfile_SpooledTemporaryFile_explicit.py
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('Questa riga viene ripetuta ad libitum.\n')
print(temp._rolled, temp._file)
print('scrittura del buffer')
temp.rollover()
print(temp._rolled, temp._file)
In questo esempio, visto che la dimensione del buffer è molto di più grande dei dati stessi, non verrebbe creato alcun file su disco se non venisse chiamato rollover()
.
$ python3 tempfile_SpooledTemporaryFile_explicit.py temp: <tempfile.SpooledTemporaryFile object at 0x7f624959f780> False <_io.StringIO object at 0x7f62495e6708> False <_io.StringIO object at 0x7f62495e6708> False <_io.StringIO object at 0x7f62495e6708> scrittura del buffer True <_io.TextIOWrapper name=3 mode='w+t' encoding='utf-8'>
Directory Temporanee
Se occorrono diversi file temporanei, potrebbe essere molto più conveniente creare una singola directory temporanea con TemporaryDirectory
, quindi aprire tutti i file in essa.
# tempfile_TemporaryDirectory.py
import pathlib
import tempfile
with tempfile.TemporaryDirectory() as directory_name:
the_dir = pathlib.Path(directory_name)
print(the_dir)
a_file = the_dir / 'un_file.txt'
a_file.write_text('Questo file viene eliminato.')
print('La directory eiste dopo?', the_dir.exists())
print('Contenuto dopo:', list(the_dir.glob('*')))
Il gestore di contesto produce il nome della directory, che può poi essere usato all'interno del blocco del contesto per costruire altri nomi di file.
$ python3 tempfile_TemporaryDirectory.py /tmp/tmpm253msqx La directory eiste dopo? False Contenuto dopo: []
Predire i nomi
Sebbene sia meno sicuro rispetto ai file temporanei strettamente anonimi, includere una porzione prevedibile nel nome consente di trovare il file ed esaminarlo per scopi di debug. Tutte le funzioni fin qui descritte ricevono tre parametri per consentire il controllo dei nomi dei file fino a un certo punto. I nomi sono generati usando la formula:
dir + prefix (prefisso) + random (casuale) + suffix (suffisso).
Tutti i valori tranne casuale
possono essere passati come argomenti delle funzioni per creare directory e file temporanei.
# tempfile_NamedTemporaryFile_args.py
import tempfile
with tempfile.NamedTemporaryFile(suffix='_suffisso',
prefix='prefisso_',
dir='/tmp') as temp:
print('temp:')
print(' ', temp)
print('temp.name:')
print(' ', temp.name)
Gli argomenti prefix
e suffix
sono combinati assieme a una stringa casuale di caratteri per costruire il nome del file, ed l'argomento dir
viene ricevuto così com'è e usato come locazione del nuovo file.
$ python3 tempfile_NamedTemporaryFile.py temp: <tempfile._TemporaryFileWrapper object at 0x7f6ba21397b8> temp.name: '/tmp/tmpmc08iq_w' Esiste dopo la chiusura: False
Locazione dei file temporanei
Se non viene specificata esplicitamente una destinazione attraverso l'argomento dir
, il percorso usato per i file temporanei assumerà valori diversi a seconda della piattaforma di esecuzione e delle impostazioni. Il modulo tempfile include due funzioni per interrogare le impostazioni che sono usate in fase di esecuzione.
# tempfile_settings.py
import tempfile
print('gettempdir():', tempfile.gettempdir())
print('gettempprefix():', tempfile.gettempprefix())
gettempdir()
restituisce la directory predefinita che conterrà tutti i file temporanei e gettempprefix()
ritorna la stringa del prefisso per i nomi del nuovo file e directory.
$ python3 tempfile_settings.py gettempdir(): /tmp gettempprefix(): tmp
Il valore restituito da gettempdir()
viene impostato in base a un algoritmo che cerca attraverso un elenco di locazioni il primo posto nel quale il processo corrente può creare un file. La lista di ricerca è:
- Il valore della variabile di ambiente
TMPDIR
- Il valore della variabile di ambiente
TEMP
- Il valore della variabile di ambiente
TMP
- Una locazione specifica rispetto alla piattaforma. (Windows usa la prima disponibile tra, le directory:
C:\temp
,C:\tmp
,\temp
, o\tmp
. Altri piattaforme usano/tmp
,/var/tmp
, o/usr/tmp
. - Se nessuna directory viene trovata, si utilizza la directory corrente.
# tempfile_tempdir.py
import tempfile
tempfile.tempdir = '/Ho/cambiato/questo/percorso'
print('gettempdir():', tempfile.gettempdir())
I programmi che devono utilizzare una locazione globale per tutti i file temporanei senza usare alcuna di queste variabili di ambiente, dovrebbero impostare tempfile.tempdir
direttamente assegnando il valore alla variabile.
$ python3 tempfile_tempdir.py gettempdir(): /Ho/cambiato/questo/percorso