Comment créer en toute sécurité un répertoire imbriqué ?

Quelle est la manière la plus élégante de vérifier si le répertoire dans lequel un fichier va être écrit existe, et si ce n'est pas le cas, de créer le répertoire en utilisant Python ? Voici ce que j'ai essayé :

import os

file_path = "/my/directory/filename.txt"
directory = os.path.dirname(file_path)

try:
    os.stat(directory)
except:
    os.mkdir(directory)       

f = file(filename)

D'une manière ou d'une autre, j'ai manqué os.path.exists (merci kanja, Blair, et Douglas). Voici ce que j'ai maintenant :

def ensure_dir(file_path):
    directory = os.path.dirname(file_path)
    if not os.path.exists(directory):
        os.makedirs(directory)

Est-ce qu'il y a un flag pour "open&quot ;, qui fait que cela arrive automatiquement ?

Solution

Je vois deux réponses avec de bonnes qualités, chacune avec un petit défaut, donc je vais donner mon point de vue sur le sujet :

Essayez [os.path.exists][1], et considérez [os.makedirs][2] pour la création.

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

Comme indiqué dans les commentaires et ailleurs, il y a une condition de course &ndash ; si le répertoire est créé entre les appels os.path.exists et os.makedirs, le os.makedirs échouera avec un OSError. Malheureusement, le fait d'attraper un OSError et de continuer n'est pas infaillible, car il ignorera un échec de création du répertoire dû à d'autres facteurs, tels que des permissions insuffisantes, un disque plein, etc.

Une option serait de piéger le OSError et d'examiner le code d'erreur intégré (voir [Is there a cross-platform way of getting information from Python's OSError][3]) :

import os, errno

try:
    os.makedirs(directory)
except OSError as e:
    if e.errno != errno.EEXIST:
        raise

Alternativement, il pourrait y avoir un second os.path.exists, mais supposez qu'un autre ait créé le répertoire après la première vérification, puis l'ait supprimé avant la seconde &ndash ; nous pourrions encore être trompés.

Selon l'application, le danger des opérations simultanées peut être plus ou moins grand que le danger posé par d'autres facteurs comme les permissions de fichiers. Le développeur devrait en savoir plus sur l'application particulière qu'il développe et son environnement attendu avant de choisir une mise en œuvre.

Les versions modernes de Python améliorent considérablement ce code, en exposant [FileExistsError][4] (dans 3.3+)...

try:
    os.makedirs("path/to/directory")
except FileExistsError:
    # directory already exists
    pass

...et en permettant [un argument mot-clé à os.makedirs appelé exist_ok][5] (en 3.2+).

os.makedirs("path/to/directory", exist_ok=True)  # succeeds even if directory exists.

[1] : https://docs.python.org/2/library/os.path.html#os.path.exists [2] : https://docs.python.org/2/library/os.html#os.makedirs [3] : https://stackoverflow.com/questions/273698/is-there-a-cross-platform-way-of-getting-information-from-pythons-oserror [4] : https://docs.python.org/3.3/library/exceptions.html?#FileExistsError [5] : https://docs.python.org/3.2/library/os.html#os.makedirs

Commentaires (8)

Vérifiez [os.makedirs][1] : (Il s'assure que le chemin complet existe). Pour gérer le fait que le répertoire puisse exister, attrapez OSError. (Si exist_ok est False (la valeur par défaut), une OSError est levée si le répertoire cible existe déjà).

import os
try:
    os.makedirs('./path/to/somewhere')
except OSError:
    pass

[1] : https://docs.python.org/3/library/os.html#os.makedirs

Commentaires (3)

Essayez la fonction [os.path.exists][1].

if not os.path.exists(dir):
    os.mkdir(dir)

[1] : https://docs.python.org/2/library/os.path.html#os.path.exists "os.path.exists" (en anglais)

Commentaires (3)