Funzionalità mkdir -p in Python [duplicato]
Domanda
Questa domanda ha già una risposta qui:
Esiste un modo per ottenere funzionalità simili a mkdir -p
sulla shell da Python. Sto cercando una soluzione diversa da una chiamata di sistema. Sono sicuro che il codice è inferiore a 20 righe e mi chiedo se qualcuno lo abbia già scritto?
Soluzione
mkdir -p
funzionalità come segue:
import errno
import os
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
Aggiornamento
Per Python & # 8805; 3.2, os.makedirs
ha un terzo argomento facoltativo exist_ok
che, se vero, abilita la funzionalità mkdir -p
& # 8212; a meno che
viene fornito e la directory esistente ha autorizzazioni diverse da quelle previste; in tal caso, OSError
viene generato come in precedenza.
Aggiornamento 2
Per Python & # 8805; 3.5, esiste anche pathlib.Path.mkdir
:
import pathlib
pathlib.Path("/tmp/path/to/desired/directory").mkdir(parents=True, exist_ok=True)
Il parametro exist_ok
è stato aggiunto in Python 3.5.
Altri suggerimenti
In Python > = 3.2, questo è
os.makedirs(path, exist_ok=True)
Nelle versioni precedenti, utilizzare @ tzot's answer .
Questo è più semplice che intrappolare l'eccezione:
import os
if not os.path.exists(...):
os.makedirs(...)
Disclaimer Questo approccio richiede due chiamate di sistema che sono più suscettibili alle condizioni di gara in determinati ambienti / condizioni. Se stai scrivendo qualcosa di più sofisticato di un semplice script usa e getta in esecuzione in un ambiente controllato, è meglio andare avanti con la risposta accettata che richiede solo una chiamata di sistema.
AGGIORNAMENTO 27/07/2012
Sono tentato di eliminare questa risposta, ma penso che ci sia un valore nel thread di commento qui sotto. Come tale, lo sto convertendo in un wiki.
Di recente, ho trovato questo distutils.dir_util.mkpath :
In [17]: from distutils.dir_util import mkpath
In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']
mkdir -p
ti dà un errore se il file esiste già:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory `/tmp/foo': File exists
Quindi un affinamento ai suggerimenti precedenti sarebbe quello di ri-codificare sollevare
se os.path.isdir
restituisce False
(quando si seleziona per errno.EEXIST
).
(Aggiornamento) Vedi anche questo domanda molto simile ; Sono d'accordo con la risposta accettata (e avvertenze) tranne per il fatto che raccomanderei os.path.isdir
invece di os.path.exists
.
(Aggiorna) Per un suggerimento nei commenti, la funzione completa sarebbe simile a:
import os
def mkdirp(directory):
if not os.path.isdir(directory):
os.makedirs(directory)
Come menzionato nelle altre soluzioni, vogliamo essere in grado di colpire il file system una volta mentre imita il comportamento di mkdir -p
. Non penso che sia possibile farlo, ma dovremmo avvicinarci il più possibile.
Codice prima, spiegazione dopo:
import os
import errno
def mkdir_p(path):
""" 'mkdir -p' in Python """
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
Dato che i commenti alla risposta di @ tzot indicano che ci sono problemi nel controllare se è possibile creare una directory prima di crearla effettivamente: non si può dire se qualcuno ha cambiato il file system nel frattempo. Ciò si adatta anche allo stile di Python di chiedere perdono, non permesso.
Quindi la prima cosa che dovremmo fare è provare a creare la directory, quindi se va storto, capire perché.
Come sottolinea Jacob Gabrielson, uno dei casi che dobbiamo cercare è il caso in cui esiste già un file in cui stiamo cercando di mettere la directory.
Con mkdir -p
:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory '/tmp/foo': File exists
Il comportamento analogo in Python sarebbe quello di sollevare un'eccezione.
Quindi dobbiamo capire se fosse così. Sfortunatamente, non possiamo. Riceviamo lo stesso messaggio di errore dai makedir se esiste una directory (buona) o esiste un file che impedisce la creazione della directory (cattiva).
L'unico modo per capire cosa è successo è ispezionare nuovamente il file system per vedere se c'è una directory lì. In tal caso, restituisci in silenzio, altrimenti solleva l'eccezione.
L'unico problema è che il file system potrebbe trovarsi in uno stato diverso ora rispetto a quando è stato chiamato makedirs. ad esempio: esiste un file che causa il fallimento dei makedir, ma ora una directory è al suo posto. Questo non ha molta importanza, perché la funzione si chiuderà silenziosamente senza sollevare un'eccezione quando al momento dell'ultima chiamata al file system esisteva la directory.
Con Pathlib dalla libreria standard di python3:
Path(mypath).mkdir(parents=True, exist_ok=True)
Se i genitori sono veri, tutti i genitori mancanti di questo percorso vengono creati come necessario; vengono creati con le autorizzazioni predefinite senza accettazione modalità in considerazione (imitando il comando POSIX mkdir -p). Se exist_ok è falso (impostazione predefinita), viene generato un FileExistsError se la directory di destinazione esiste già.
Se exist_ok è true, le eccezioni FileExistsError verranno ignorate (stesso comportamento come comando POSIX mkdir -p), ma solo se l'ultimo percorso componente non è un file non di directory esistente.
Modificato nella versione 3.5: è stato aggiunto il parametro exist_ok.
Penso che la risposta di Asa sia essenzialmente corretta, ma potresti estenderla un po 'per agire più come mkdir -p
,
import os
def mkdir_path(path):
if not os.access(path, os.F_OK):
os.mkdirs(path)
o
import os
import errno
def mkdir_path(path):
try:
os.mkdirs(path)
except os.error, e:
if e.errno != errno.EEXIST:
raise
Entrambi gestiscono il caso in cui il percorso esiste già in silenzio ma lasciano apparire altri errori.
Dichiarazione di funzione;
import os
def mkdir_p(filename):
try:
folder=os.path.dirname(filename)
if not os.path.exists(folder):
os.makedirs(folder)
return True
except:
return False
utilizzo:
filename = "./download/80c16ee665c8/upload/backup/mysql/2014-12-22/adclient_sql_2014-12-22-13-38.sql.gz"
if (mkdir_p(filename):
print "Created dir :%s" % (os.path.dirname(filename))
Ho avuto successo con quanto segue personalmente, ma la mia funzione dovrebbe probabilmente essere chiamata come "assicurati che questa directory esista":
def mkdirRecursive(dirpath):
import os
if os.path.isdir(dirpath): return
h,t = os.path.split(dirpath) # head/tail
if not os.path.isdir(h):
mkdirRecursive(h)
os.mkdir(join(h,t))
# end mkdirRecursive
import os
import tempfile
path = tempfile.mktemp(dir=path)
os.makedirs(path)
os.rmdir(path)
import os
from os.path import join as join_paths
def mk_dir_recursive(dir_path):
if os.path.isdir(dir_path):
return
h, t = os.path.split(dir_path) # head/tail
if not os.path.isdir(h):
mk_dir_recursive(h)
new_path = join_paths(h, t)
if not os.path.isdir(new_path):
os.mkdir(new_path)
basato sulla risposta di @Dave C ma con un bug risolto in cui parte dell'albero esiste già