Fonctionnalité mkdir -p en Python [dupliquer]
Question
Cette question a déjà une réponse ici:
Existe-t-il un moyen d'obtenir une fonctionnalité similaire à mkdir -p
sur le shell à partir de Python. Je cherche une solution autre qu'un appel système. Je suis sûr que le code fait moins de 20 lignes et je me demande si quelqu'un l'a déjà écrit?
La solution
mkdir -p
comme suit:
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
Mettre à jour
Pour Python & # 8805; 3.2, os.makedirs
a un troisième argument facultatif exist_ok
qui, lorsque la valeur est true, active la fonctionnalité mkdir -p
& # 8212; sauf si
est fourni et le répertoire existant a des autorisations différentes de celles prévues. dans ce cas, OSError
est généré comme précédemment.
Mise à jour 2
Pour Python & # 8805; 3.5, il existe également pathlib.Path.mkdir
:
import pathlib
pathlib.Path("/tmp/path/to/desired/directory").mkdir(parents=True, exist_ok=True)
Le paramètre exist_ok
a été ajouté dans Python 3.5.
Autres conseils
En Python > = 3.2, c'est
os.makedirs(path, exist_ok=True)
Dans les versions antérieures, utilisez la réponse de @ tzot .
C'est plus facile que de piéger l'exception:
import os
if not os.path.exists(...):
os.makedirs(...)
Clause de non-responsabilité : cette approche nécessite deux appels système plus sensibles aux conditions de concurrence dans certains environnements. Si vous écrivez quelque chose de plus sophistiqué qu'un simple script jetable exécuté dans un environnement contrôlé, vous feriez mieux de choisir la réponse acceptée qui ne nécessite qu'un seul appel système.
MISE À JOUR 2012-07-27
Je suis tenté de supprimer cette réponse, mais je pense que le fil de commentaire ci-dessous présente un intérêt. En tant que tel, je le convertis en wiki.
Récemment, j'ai trouvé ce distutils.dir_util.mkpath :
In [17]: from distutils.dir_util import mkpath
In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']
mkdir -p
vous donne une erreur si le fichier existe déjà:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory `/tmp/foo': File exists
Donc, un raffinement aux suggestions précédentes consisterait à relancer
si os.path.isdir
renvoie False
(lors de la vérification pour errno.EEXIST
).
(Mise à jour) Voir aussi ceci question très similaire ; Je suis d'accord avec la réponse acceptée (et les mises en garde), sauf que je recommanderais os.path.isdir
au lieu de os.path.exists
.
(Mise à jour) Selon une suggestion dans les commentaires, la fonction complète ressemblerait à:
import os
def mkdirp(directory):
if not os.path.isdir(directory):
os.makedirs(directory)
Comme indiqué dans les autres solutions, nous souhaitons pouvoir accéder au système de fichiers une fois tout en imitant le comportement de mkdir -p
. Je ne pense pas que cela soit possible, mais nous devrions nous rapprocher le plus possible.
Code d'abord, explication plus tard:
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
Comme l'indiquent les réponses à la question de @ tzot, il est difficile de vérifier si vous pouvez créer un répertoire avant de le créer: vous ne pouvez pas savoir si quelqu'un a modifié le système de fichiers entre-temps. Cela correspond également au style de demande de pardon et non de permission de Python.
Donc, la première chose à faire est d'essayer de créer le répertoire. Si cela ne fonctionne pas, essayez de comprendre pourquoi.
Comme le souligne Jacob Gabrielson, l’un des cas à rechercher est le cas où il existe déjà un fichier dans lequel nous essayons de mettre le répertoire.
Avec mkdir -p
:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory '/tmp/foo': File exists
Le comportement analogue en Python serait de déclencher une exception.
Nous devons donc déterminer si tel était le cas. Malheureusement, nous ne pouvons pas. Nous recevons le même message d'erreur de la part de makedirs, qu'il existe un répertoire (correct) ou un fichier empêchant la création du répertoire (incorrect).
La seule façon de savoir ce qui s'est passé est d'inspecter à nouveau le système de fichiers pour voir s'il existe un répertoire. Si tel est le cas, retournez en mode silencieux, sinon, déclenchez l'exception.
Le seul problème est que le système de fichiers peut maintenant être dans un état différent de celui auquel l'appelait makedirs. Exemple: un fichier existait, ce qui entraînait l'échec de makedirs, mais maintenant un répertoire est à sa place. Cela n’a pas beaucoup d’importance, car la fonction ne se fermera que de manière silencieuse sans déclencher une exception si, au moment du dernier appel du système de fichiers, le répertoire existait.
Avec Pathlib de la bibliothèque standard python3:
Path(mypath).mkdir(parents=True, exist_ok=True)
Si parents est vrai, tous les parents manquants de ce chemin sont créés en tant que nécessaire; ils sont créés avec les autorisations par défaut sans prendre mode en compte (imitant la commande POSIX mkdir -p). Si exist_ok est false (valeur par défaut), une erreur FileExistsError est déclenchée si le répertoire cible existe déjà.
Si exist_ok est true, les exceptions FileExistsError seront ignorées (idem comportement que la commande POSIX mkdir -p), mais uniquement si le dernier chemin composant n'est pas un fichier non-répertoire existant.
Modifié dans la version 3.5: le paramètre exist_ok a été ajouté.
Je pense que la réponse d'Asa est essentiellement correcte, mais vous pouvez l'étendre un peu pour qu'elle ressemble davantage à mkdir -p
, soit:
import os
def mkdir_path(path):
if not os.access(path, os.F_OK):
os.mkdirs(path)
ou
import os
import errno
def mkdir_path(path):
try:
os.mkdirs(path)
except os.error, e:
if e.errno != errno.EEXIST:
raise
Ces deux solutions gèrent le cas où le chemin existe déjà en mode silencieux tout en laissant les autres erreurs disparaître.
Déclaration de fonction;
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
utilisation:
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))
J'ai personnellement eu du succès avec ce qui suit, mais ma fonction devrait probablement s'appeler quelque chose comme "s'assurer que ce répertoire existe":
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)
basé sur la réponse de @Dave C mais avec un bogue corrigé lorsqu'une partie de l'arbre existe déjà