Comment puis-je créer en toute sécurité un répertoire imbriqué en Python?

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 à l'aide de 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 façon ou d'une autre, j'ai raté os.path.exists (merci kanja, Blair, et Douglas). C'est 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)

y a-t-il un drapeau pour "ouvrir", qui fait que cela se produit automatiquement?

3097
demandé sur A-B-B 2008-11-07 21:56:45

25 réponses

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 elle:

Essayer os.path.exists , et de considérer os.makedirs pour la création.

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

tel que noté dans les commentaires et ailleurs, il y a une condition de race - si le répertoire est créé entre les appels os.path.exists et os.makedirs , le os.makedirs échouera avec un OSError . Malheureusement, attraper OSError et continuer n'est pas infaillible, car il ignorera un échec de créer le répertoire en raison d'autres facteurs, tels que des permissions insuffisantes, disque complet, etc.

une option serait de piéger le OSError et d'examiner le code d'erreur intégré (voir y a-t-il un moyen multiplateforme d'obtenir des informations à partir de L'OSError de Python ):

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 supposons qu'un autre crée le répertoire après la première vérification, puis le supprime avant la seconde - nous pourrions encore être dupé.

selon la demande, le danger des opérations simultanées peut être plus ou moins grand que le danger présenté par d'autres facteurs tels que les permissions de fichiers. Le développeur devrait en savoir plus sur l'application particulière en cours de développement et son environnement prévu avant de choisir une mise en œuvre.

3824
répondu Blair Conrad 2018-03-30 21:11:30

Python 3.5+:

import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True) 

pathlib.Path.mkdir comme utilisé ci-dessus crée récursivement le répertoire et ne soulève pas d'exception si le répertoire existe déjà. Si vous n'avez pas besoin ou voulez que les parents soient créés, sautez l'argument parents .

Python 3.2+:

utilisant pathlib :

si vous pouvez, installez le courant pathlib pathlib2 . N'installez pas l'ancien port non maintenu nommé pathlib . Ensuite, reportez-vous à la section Python 3.5+ ci-dessus et utilisez-la de la même manière.

si vous utilisez Python 3.4, même s'il est livré avec pathlib , il manque l'option utile exist_ok . Le backport est destiné à offrir une implémentation plus récente et supérieure de mkdir qui inclut cette option manquante.

utilisant os :

import os
os.makedirs(path, exist_ok=True)

os.makedirs comme utilisé ci-dessus crée récursivement le répertoire et ne soulève pas d'exception si le répertoire existe déjà. Il a l'argument optionnel exist_ok seulement si vous utilisez Python 3.2+, avec une valeur par défaut de False . Cet argument n'existe pas en Python 2.x jusqu'à 2,7. Par conséquent, il n'est pas nécessaire de faire une exception manuelle manipulation comme avec Python 2.7.

Python 2.7+:

utilisant pathlib :

si vous le pouvez, installez le backport actuel pathlib nommé pathlib2 . N'installez pas l'ancien port non maintenu nommé pathlib . Ensuite, reportez-vous à la section Python 3.5+ ci-dessus et utilisez-la de la même manière.

à l'Aide de os :

import os
try: 
    os.makedirs(path)
except OSError:
    if not os.path.isdir(path):
        raise

alors qu'une solution naïve peut d'abord utiliser os.path.isdir suivi de os.makedirs , la solution ci-dessus inverse l'ordre des deux opérations. Ce faisant, il empêche une condition de course commune ayant à faire avec une tentative dupliquée de créer le répertoire, et désambiguise également les fichiers à partir de répertoires.

noter que la saisie de l'exception et l'utilisation de errno est d'une utilité limitée parce que OSError: [Errno 17] File exists , i.e. errno.EEXIST , est soulevé à la fois pour les fichiers et les répertoires. Il est plus fiable simplement de vérifier si le répertoire existe.

Alternative:

mkpath crée le répertoire imbriqué, et ne fait rien si le répertoire existe déjà. Cela fonctionne en Python 2 et 3.

import distutils.dir_util
distutils.dir_util.mkpath(path)

Par Bogue 10948 , une limitation sévère de cette alternative est qu'elle ne fonctionne qu'une seule fois par processus python pour un chemin donné. En d'autres termes, si vous l'utilisez pour créer un répertoire, puis supprimez le répertoire de L'intérieur ou de l'extérieur de Python, puis utilisez mkpath à nouveau pour recréer le même répertoire, mkpath utilisera simplement silencieusement son information mise en cache invalide d'avoir précédemment créé le répertoire, et ne fera pas réellement le répertoire à nouveau. En revanche, os.makedirs ne repose sur aucun mettre en cache. Cette limitation peut être acceptable pour certaines applications.


en ce qui concerne le mode du répertoire , veuillez vous référer à la documentation Si vous vous souciez de celle-ci.

868
répondu A-B-B 2018-05-17 17:16:23

en utilisant try except et le bon code d'erreur du module errno se débarrasse de la condition de course et est cross-platform:

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST:
            raise

En d'autres termes, nous essayons de créer les répertoires, mais si elles existent déjà pour ignorer l'erreur. D'autre part, toute autre erreur est signalée. Par exemple, si vous créez dir 'a' à l'avance et supprimez toutes les permissions, vous obtiendrez un OSError augmenté de errno.EACCES (Permission refusée, erreur 13).

582
répondu Heikki Toivonen 2017-04-24 01:55:54

je vous recommande personnellement d'utiliser os.path.isdir() pour tester au lieu de os.path.exists() .

>>> os.path.exists('/tmp/dirname')
True
>>> os.path.exists('/tmp/dirname/filename.etc')
True
>>> os.path.isdir('/tmp/dirname/filename.etc')
False
>>> os.path.isdir('/tmp/fakedirname')
False

si vous avez:

>>> dir = raw_input(":: ")

et une entrée d'utilisateur stupide:

:: /tmp/dirname/filename.etc

... Vous allez finir avec un répertoire nommé filename.etc lorsque vous transmettez argument os.makedirs() si vous testez avec os.path.exists() .

90
répondu Peter Mortensen 2014-05-31 14:06:06

Vérifier os.makedirs : (il s'assure que le chemin complet existe.)

Pour gérer le fait que le répertoire pourrait exister, attrapez OSError. (Si exist_ok est False (par défaut), une OSError est soulevée si le répertoire cible existe déjà.)

import os
try:
    os.makedirs('./path/to/somewhere')
except OSError:
    pass
60
répondu Douglas Mayle 2017-11-15 02:25:56

Aperçus sur les spécificités de cette situation

vous donnez un fichier particulier à un certain chemin et vous tirez le répertoire du chemin du fichier. Puis, après vous être assuré que vous avez le répertoire, vous tentez d'ouvrir un fichier pour le lire. Pour commenter ce code:

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

nous voulons éviter de surcharger la fonction builtin, dir . En outre, filepath ou peut-être fullfilepath est probablement une meilleure nom sémantique que filename donc ce serait mieux écrit:

import os
filepath = '/my/directory/filename.txt'
directory = os.path.dirname(filepath)

votre objectif final est d'ouvrir ce fichier, vous déclarez d'abord, pour l'écriture, mais vous vous approchez essentiellement de cet objectif (basé sur votre code) comme ceci, qui ouvre le fichier pour lecture :

if not os.path.exists(directory):
    os.makedirs(directory)
f = file(filename)

supposant ouverture pour lecture

Pourquoi créer un répertoire pour un fichier qui vous vous attendez à être là et être capable de lire?

Juste essayer d'ouvrir le fichier.

with open(filepath) as my_file:
    do_stuff(my_file)

si le répertoire ou le fichier n'est pas là, vous obtiendrez un IOError avec un numéro d'erreur associé: errno.ENOENT pointera vers le numéro d'erreur correct quelle que soit votre plate-forme. Vous pouvez l'attraper si vous voulez, par exemple:

import errno
try:
    with open(filepath) as my_file:
        do_stuff(my_file)
except IOError as error:
    if error.errno == errno.ENOENT:
        print 'ignoring error because directory or file is not there'
    else:
        raise

en supposant que nous ouvrons pour l'écriture

C'est probablement ce que vous voulez.

dans ce cas, nous ne sommes probablement pas confrontés à des conditions de course. Alors faites comme vous l'étiez, mais notez que pour écrire, vous devez ouvrir avec le mode w (ou a pour ajouter). C'est aussi une bonne pratique Python d'utiliser le gestionnaire de contexte pour ouvrir des fichiers.

import os
if not os.path.exists(directory):
    os.makedirs(directory)
with open(filepath, 'w') as my_file:
    do_stuff(my_file)

cependant, disons que nous avons plusieurs processus Python qui tentent de mettre toutes leurs données dans le même répertoire. Alors nous pouvons avoir des disputes sur la création du répertoire. Dans ce cas, il est préférable d'envelopper l'appel makedirs dans un bloc d'essai.

import os
import errno
if not os.path.exists(directory):
    try:
        os.makedirs(directory)
    except OSError as error:
        if error.errno != errno.EEXIST:
            raise
with open(filepath, 'w') as my_file:
    do_stuff(my_file)
33
répondu Aaron Hall 2016-04-01 21:54:27

à partir de Python 3.5, pathlib.Path.mkdir a un exist_ok drapeau:

from pathlib import Path
path = Path('/my/directory/filename.txt')
path.parent.mkdir(parents=True, exist_ok=True) 
# path.parent ~ os.path.dirname(path)

cela crée de façon récursive le répertoire et ne soulève pas d'exception si le répertoire existe déjà.

(tout comme os.makedirs a obtenu un drapeau exists_ok à partir de python 3.2).

32
répondu hiro protagonist 2018-03-29 09:49:40

essayez la os.path.exists fonction

if not os.path.exists(dir):
    os.mkdir(dir)
25
répondu gone 2015-10-15 16:05:12

j'ai noté ce qui suit. Il n'est pas totalement infaillible.

import os

dirname = 'create/me'

try:
    os.makedirs(dirname)
except OSError:
    if os.path.exists(dirname):
        # We are nearly safe
        pass
    else:
        # There was an error on creation, so make sure we know about it
        raise

maintenant, comme je le dis, ce n'est pas vraiment infaillible, parce que nous avons la possibilité de ne pas créer le répertoire, et un autre processus le créant pendant cette période.

24
répondu Ali Afshar 2014-05-31 14:05:11

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

la réponse directe à cette question Est, en supposant une situation simple où vous ne vous attendez pas à ce que d'autres utilisateurs ou processus interfèrent avec votre répertoire:

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

ou si le répertoire est soumise à des conditions de course (c'est à dire si après avoir vérifié le chemin d'accès existe, quelque chose d'autre peut avoir déjà fait) faire ceci:

import errno
try:
    os.makedirs(d)
except OSError as exception:
    if exception.errno != errno.EEXIST:
        raise

mais peut-être une approche encore meilleure est d'éviter la question de la prétention des ressources, en utilisant des répertoires temporaires via tempfile :

import tempfile

d = tempfile.mkdtemp()

Voici l'essentiel de la doc en ligne:

mkdtemp(suffix='', prefix='tmp', dir=None)
    User-callable function to create and return a unique temporary
    directory.  The return value is the pathname of the directory.

    The directory is readable, writable, and searchable only by the
    creating user.

    Caller is responsible for deleting the directory when done with it.

nouveau en Python 3.5: pathlib.Path avec exist_ok

il y a un nouveau Path objet (3.4) avec beaucoup de méthodes pour utiliser avec les chemins, dont l'un est mkdir .

(pour le contexte, je traque mon représentant hebdomadaire avec un script. Voici les parties pertinentes du code du script qui me permettent d'éviter de frapper le débordement de la pile plus d'une fois par jour pour les mêmes données.)

tout d'abord les importations concernées:

from pathlib import Path
import tempfile

nous n'avons pas à traiter avec os.path.join maintenant - juste joindre les parties de chemin avec un / :

directory = Path(tempfile.gettempdir()) / 'sodata'

alors je m'assure que le répertoire existe-l'argument exist_ok apparaît en Python 3.5:

directory.mkdir(exist_ok=True)

Voici la partie pertinente de la documentation :

si exist_ok est vrai, FileExistsError les exceptions seront ignorées( même comportement que la commande POSIX mkdir -p ), mais seulement si le dernier chemin component n'est pas un fichier non répertoire existant.

voici un peu plus du script - dans mon cas, je ne suis pas soumis à une condition de race, je n'ai qu'un seul processus qui s'attend à ce que le répertoire (ou les fichiers contenus) soit là, et je n'ai rien qui essaye de supprimer le répertoire.

todays_file = directory / str(datetime.datetime.utcnow().date())
if todays_file.exists():
    logger.info("todays_file exists: " + str(todays_file))
    df = pd.read_json(str(todays_file))

Path les objets doivent être forcés à str avant que d'autres API qui attendent str chemins peuvent les utiliser.

peut-être que Pandas devrait être mis à jour pour accepter les instances de la classe de base abstraite, os.PathLike .

17
répondu Aaron Hall 2017-07-07 03:19:31

en Python 3.4 vous pouvez également utiliser le tout neuf pathlib module :

from pathlib import Path
path = Path("/my/directory/filename.txt")
try:
    if not path.parent.exists():
        path.parent.mkdir(parents=True)
except OSError:
    # handle error; you can also catch specific errors like
    # FileExistsError and so on.
15
répondu Antti Haapala 2015-03-11 20:50:01

le documentation Python pertinente suggère l'utilisation du style de codage EAFP (plus facile à 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 mieux que l'alternative

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

la documentation le suggère précisément à cause de la condition de race discutée dans cette question. En outre, comme d'autres le mentionnent ici, il y a un avantage de performance en interrogeant une fois au lieu de deux fois l'OS. 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 est exécutée-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, c'est une mauvaise pratique qui peut conduire à un débogage inutile depuis longtemps. Par exemple, le fait que nous avons mis l' les permissions pour un répertoire ne devraient pas nous laisser l'impression que les permissions sont définies de manière appropriée pour nos buts. Un répertoire parent peut être monté avec d'autres permissions. En général, un programme doit toujours fonctionner correctement et que le programmeur ne doit pas s'attendre à un environnement spécifique.

9
répondu kavadias 2017-12-31 03:12:48

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 va aussi créer les répertoires des ancêtres.

ça marche pour Python 2 et 3.

7
répondu Dennis Golomazov 2016-09-13 21:44:56

dans Python3 , os.makedirs supporte la configuration exist_ok . Le paramètre par défaut est False , ce qui signifie qu'un OSError sera augmenté si le répertoire cible existe déjà. En définissant exist_ok à True , OSError (répertoire existe) sera ignoré et le répertoire ne sera pas créé.

os.makedirs(path,exist_ok=True)

Dans Python2 , os.makedirs ne prend pas en charge la définition de exist_ok . Vous pouvez utiliser l'approche de heikki-toivonen la réponse de :

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST:
            raise
7
répondu euccas 2017-05-23 12:26:31

pour une solution monocouche, vous pouvez utiliser IPython.utils.path.ensure_dir_exists() :

from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)

De la documentation : s'Assurer que le répertoire existe. Si elle n'existe pas, essayez de la créer et protégez-vous contre une condition de race si un autre processus fait la même chose.

6
répondu tashuhka 2016-03-30 07:31:02

j'utilise os.path.exists() , ici est un script Python 3 qui peut être utilisé pour vérifier si un répertoire existe, en créer un s'il n'existe pas, et le supprimer s'il existe (si désiré).

il invite les utilisateurs à entrer dans le répertoire et peut être facilement modifié.

6
répondu Michael Strobel 2017-12-31 03:16:11

j'ai trouvé cette question/réponse et j'ai été initialement perplexe par certains des échecs et des erreurs que je recevais. Je travaille en Python 3 (v. 3.5 dans un environnement virtuel Anaconda sur un système Arch Linux x86_64).

Considérer cette structure de répertoire:

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

Voici mes expériences / notes, qui clarifient les choses:

# ----------------------------------------------------------------------------
# [1] /q/how-can-i-safely-create-a-nested-directory-in-python-5312/""" 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 un répertoire s'il n'existe pas?

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

5
répondu Victoria Stuart 2017-12-16 19:26:08

j'ai vu Heikki Toivonen et A-B-B 's réponses et de la pensée de cette variation.

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST or not os.path.isdir(path):
            raise
5
répondu alissonmuller 2017-12-31 03:14:29

vous pouvez utiliser os.listdir pour ceci:

import os
if 'dirName' in os.listdir('parentFolderPath')
    print('Directory Exists')
4
répondu iPhynx 2017-09-30 12:31:13

lorsque vous travaillez avec file I / O, la chose importante à considérer est

TOCTTOU (le temps de vérifier au moment de l'utilisation)

donc faire un chèque avec if et ensuite lire ou écrire plus tard peut se retrouver dans une exception d'E/S sans retenue. La meilleure façon de le faire est:

try:
    os.makedirs(dir_path)
except OSError as e:
    if e.errno != errno.EEXIS:
        raise
4
répondu SHAHS 2017-12-31 03:17:24

si vous considérez ce qui suit:

os.path.isdir('/tmp/dirname')

signifie un répertoire (chemin) existe et est un répertoire. Donc pour moi, cette façon fait ce dont j'ai besoin. Donc je peux m'assurer que c'est un dossier (pas un fichier) et qu'il existe.

2
répondu Ralph Schwerdt 2016-12-03 16:35:48

utilisez cette commande vérifier et créer dir

 if not os.path.isdir(test_img_dir):
     os.mkdir(str("./"+test_img_dir))
1
répondu Manivannan Murugavel 2018-04-16 07:30:10

Appeler la fonction create_dir() au point d'entrée de votre programme/projet.

import os

def create_dir(directory):
    if not os.path.exists(directory):
        print('Creating Directory '+directory)
        os.makedirs(directory)

create_dir('Project directory')
1
répondu Steffi Keran Rani J 2018-04-28 16:00:40

pourquoi ne pas utiliser le module subprocess s'il tourne sur une machine qui supporte des langages shell? Fonctionne sur python 2.7 et Python 3.6

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

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

1
répondu Geoff Paul Bremner 2018-09-11 18:55:24
import os
if os.path.isfile(filename):
    print "file exists"
else:
    "Your code here"

où votre code ici est utiliser la commande (touch)

ceci vérifiera si le fichier est là s'il ne l'est pas alors il le créera.

-1
répondu Evil Exists 2017-07-05 23:15:27