web-dev-qa-db-fra.com

Fonctionnalités mkdir -p dans Python

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?

724
SetJmp

_mkdir -p_ fonctionnalité 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
_

Mise à jour

Pour Python ≥ 3.2, _os.makedirs_ a un troisième argument optionnel _exist_ok_ qui, lorsque la valeur est true, active la fonctionnalité _mkdir -p_ - sauf si mode est fourni et que le répertoire existant dispose d'autorisations différentes de celles prévues. dans ce cas, OSError est soulevé comme précédemment.

Mise à jour 2

Pour Python ≥ 3.5, il y a aussi 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.

997
tzot

Dans Python> = 3.2, c'est

os.makedirs(path, exist_ok=True)

Dans les versions antérieures, utilisez réponse de @ tzot .

253
Fred Foo

C'est plus facile que de piéger l'exception:

import os
if not os.path.exists(...):
    os.makedirs(...)

Disclaimer Cette approche nécessite deux appels système qui sont plus sensibles aux conditions de concurrence dans certains environnements/conditions. Si vous écrivez quelque chose de plus sophistiqué qu'un simple script jetable exécuté dans un environnement contrôlé, vous feriez mieux d'utiliser 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.

154
Joe Holloway

Récemment, j'ai trouvé ceci distutils.dir_util.mkpath :

In [17]: from distutils.dir_util import mkpath

In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']
47
auraham

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 à re_raise l'exception si os.path.isdir renvoie False (lors de la recherche de 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 à ceci:

import os
def mkdirp(directory):
    if not os.path.isdir(directory):
        os.makedirs(directory) 
18
Jacob Gabrielson

Avec Pathlib de la bibliothèque standard python3:

Path(mypath).mkdir(parents=True, exist_ok=True)

Si les parents sont vrais, tous les parents manquants de ce chemin sont créés au besoin; ils sont créés avec les autorisations par défaut sans prendre en compte le mode (imitant la commande POSIX mkdir -p). Si exist_ok a la valeur false (valeur par défaut), une erreur FileExistsError est générée si le répertoire cible existe déjà.

Si exist_ok a la valeur true, les exceptions FileExistsError seront ignorées (même comportement que la commande POSIX mkdir -p), mais uniquement si le dernier composant de chemin d'accès n'est pas un fichier existant, autre qu'un répertoire.

Modifié dans la version 3.5: Le paramètre exist_ok a été ajouté.

14
Ali SAID OMAR

Comme indiqué dans les autres solutions, nous voulons pouvoir utiliser le 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 commentaires de la réponse 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 Python qui consiste à demander pardon, et non une permission.

Donc, la première chose à faire est d'essayer de créer le répertoire, puis, en cas de problème, de déterminer 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 dans Python serait de déclencher une exception.

Nous devons donc déterminer si tel était le cas. Malheureusement, nous ne pouvons pas. Makedirs nous renvoie le même message d'erreur, 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, revenez en silence, 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 vraiment pas beaucoup d’importance, car la fonction ne se fermera que silencieusement sans déclencher une exception si, au moment du dernier appel du système de fichiers, le répertoire existait déjà.

14
c4m3lo

Je pense que la réponse d’Asa est essentiellement correcte, mais vous pouvez l’étendre un peu pour qu’elle se comporte davantage comme 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à de manière silencieuse, tout en laissant les autres erreurs disparaître.

12
davidavr

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))
7
Guray Celik

Personnellement, j’ai eu du succès avec ce qui suit, mais ma fonction devrait probablement s’appeler "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
4
Dave C
import os
import tempfile

path = tempfile.mktemp(dir=path)
os.makedirs(path)
os.rmdir(path)
3
pixelbeat
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à

2
Dave00Galloway