5491 votes

Vérifier si un répertoire existe et de le créer si nécessaire

Quelle est la façon la plus élégante pour vérifier si le répertoire d'un fichier va être écrit existe, et si pas, créez le répertoire? Voici ce que j'ai essayé:

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

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

f = file(filename)

D'une certaine manière, j'ai manqué os.path.exists (merci kanja, Blair, et Douglas). C'est ce que j'ai maintenant:

def ensure_dir(f):
    d = os.path.dirname(f)
    if not os.path.exists(d):
        os.makedirs(d)

Est-il un drapeau "open", qui fait de ce lieu automatiquement?

40 votes

En général, vous devrez tenir compte du cas où le nom du fichier ne contient pas de répertoire. Sur ma machine, dirname('foo.txt') donne '', qui n'existe pas et fait échouer makedirs().

14 votes

Dans python 2.7 os.path.mkdir n'existe pas. C'est os.mkdir .

9 votes

Si le chemin existe il faut non seulement vérifier si c'est un répertoire et non un fichier normal ou un autre objet (beaucoup de réponses vérifient cela) mais il faut aussi vérifier s'il est accessible en écriture (je n'ai pas trouvé de réponse qui vérifie cela).

20voto

kavadias Points 11

El la documentation Python pertinente suggère l'utilisation de la Style de codage EAFP (Il est plus facile de demander le pardon que la permission) . Cela signifie que le code

try:
    os.makedirs(path)
except OSError as exception:
    if exception.errno != errno.EEXIST:
        raise
    else:
        print "\nBE CAREFUL! Directory %s already exists." % path

est meilleure que l'alternative

if not os.path.exists(path):
    os.makedirs(path)
else:
    print "\nBE CAREFUL! Directory %s already exists." % path

La documentation suggère cela exactement à cause de la condition de course discutée dans cette question. En outre, comme d'autres l'ont mentionné ici, il y a un avantage en termes de performances à interroger une fois le système d'exploitation au lieu de deux. Enfin, l'argument avancé, potentiellement, en faveur du second code dans certains cas - lorsque le développeur connaît l'environnement dans lequel l'application s'exécute - ne peut être défendu que dans le cas particulier où le programme a créé un environnement privé pour lui-même (et d'autres instances du même programme).

Même dans ce cas, il s'agit d'une mauvaise pratique qui peut conduire à un long débogage inutile. Par exemple, le fait que nous définissions les permissions d'un répertoire ne doit pas nous donner l'impression que les permissions sont définies de manière appropriée pour nos besoins. Un répertoire parent pourrait être monté avec d'autres permissions. En général, un programme devrait toujours fonctionner correctement et le programmeur ne devrait pas s'attendre à un environnement spécifique.

14voto

Victoria Stuart Points 21

J'ai trouvé cette question-réponse après avoir été intrigué par certaines défaillances et erreurs que j'obtenais en travaillant avec des répertoires en Python. Je travaille en Python 3 (v.3.5 dans un environnement virtuel Anaconda sur un système Arch Linux x86_64).

Considérez cette structure de répertoire :

└── output/         ## dir
   ├── corpus       ## file
   ├── corpus2/     ## dir
   └── subdir/      ## dir

Voici mes expériences/notes, qui apportent des précisions :

# ----------------------------------------------------------------------------
# [1] https://stackoverflow.com/questions/273192/how-can-i-create-a-directory-if-it-does-not-exist

import pathlib

""" Notes:
        1.  Include a trailing slash at the end of the directory path
            ("Method 1," below).
        2.  If a subdirectory in your intended path matches an existing file
            with same name, you will get the following error:
            "NotADirectoryError: [Errno 20] Not a directory:" ...
"""
# Uncomment and try each of these "out_dir" paths, singly:

# ----------------------------------------------------------------------------
# METHOD 1:
# Re-running does not overwrite existing directories and files; no errors.

# out_dir = 'output/corpus3'                ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/'               ## works
# out_dir = 'output/corpus3/doc1'           ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/doc1/'          ## works
# out_dir = 'output/corpus3/doc1/doc.txt'   ## no error but no file created (os.makedirs creates dir, not files!  ;-)
# out_dir = 'output/corpus2/tfidf/'         ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/'         ## works
# out_dir = 'output/corpus3/a/b/c/d/'       ## works

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

# Uncomment these to run "Method 1":

#directory = os.path.dirname(out_dir)
#os.makedirs(directory, mode=0o777, exist_ok=True)

# ----------------------------------------------------------------------------
# METHOD 2:
# Re-running does not overwrite existing directories and files; no errors.

# out_dir = 'output/corpus3'                ## works
# out_dir = 'output/corpus3/'               ## works
# out_dir = 'output/corpus3/doc1'           ## works
# out_dir = 'output/corpus3/doc1/'          ## works
# out_dir = 'output/corpus3/doc1/doc.txt'   ## no error but creates a .../doc.txt./ dir
# out_dir = 'output/corpus2/tfidf/'         ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/'         ## works
# out_dir = 'output/corpus3/a/b/c/d/'       ## works

# Uncomment these to run "Method 2":

#import os, errno
#try:
#       os.makedirs(out_dir)
#except OSError as e:
#       if e.errno != errno.EEXIST:
#               raise
# ----------------------------------------------------------------------------

Conclusion : à mon avis, la " méthode 2 " est plus robuste.

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

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

13voto

Denis Golomazov Points 1211

Vous pouvez utiliser mkpath

# Create a directory and any missing ancestor directories. 
# If the directory already exists, do nothing.

from distutils.dir_util import mkpath
mkpath("test")    

Notez qu'il créera également les répertoires ancêtres.

Il fonctionne pour Python 2 et 3.

11voto

Dans le cas où vous écrivez un fichier dans un chemin variable, vous pouvez utiliser ceci sur le chemin du fichier pour vous assurer que les répertoires parents sont créés.

from pathlib import Path

path_to_file = Path("zero/or/more/directories/file.ext")
parent_directory_of_file = path_to_file.parent
parent_directory_of_file.mkdir(parents=True, exist_ok=True)

Fonctionne même si path_to_file est file.ext (zéro répertoire en profondeur).

Voir pathlib.PurePath.parent y pathlib.Path.mkdir .

10voto

Pourquoi ne pas utiliser le module de sous-processus si l'on travaille sur une machine qui supporte la commande mkdir avec -p option ? Fonctionne sur python 2.7 et python 3.6

from subprocess import call
call(['mkdir', '-p', 'path1/path2/path3'])

Cela devrait faire l'affaire sur la plupart des systèmes.

Dans les situations où la portabilité n'a pas d'importance (ex, utilisation de Docker), la solution se résume à 2 lignes. Vous n'avez pas non plus besoin d'ajouter une logique pour vérifier si les répertoires existent ou non. Enfin, il est sûr de réexécuter sans aucun effet secondaire.

Si vous avez besoin d'une gestion des erreurs :

from subprocess import check_call
try:
    check_call(['mkdir', '-p', 'path1/path2/path3'])
except:
    handle...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X