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).

109voto

Douglas Mayle Points 7216

Vérifiez os.makedirs : (Il s'assure que le chemin complet existe).
Pour gérer le fait que le répertoire puisse exister, on attrape OSError . (Si exist_ok est False (par défaut), un OSError est soulevé si le répertoire cible existe déjà).

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

25 votes

Avec le try/except, vous masquerez les erreurs de création de répertoire, dans le cas où le répertoire n'existe pas mais que pour une raison ou une autre vous ne pouvez pas le faire.

4 votes

OSError sera soulevée ici si le chemin est un fichier ou un répertoire existant. J'ai publié une réponse à ce sujet.

5 votes

C'est à mi-chemin. Vous devez vérifier l'état de sous-erreur de OSError avant de décider de l'ignorer. Voir stackoverflow.com/a/5032238/763269 .

83voto

kanja Points 1422

Essayez le os.path.exists fonction

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

61voto

Aaron Hall Points 7381

Éclairage sur les particularités de cette situation

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

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

Nous voulons éviter d'écraser la fonction intégrée, dir . Aussi, filepath ou peut-être fullfilepath est probablement un meilleur nom sémantique que filename pour que ce soit mieux écrit :

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

Votre objectif final est d'ouvrir ce fichier, comme vous l'avez indiqué initialement, pour l'écriture, mais vous approchez essentiellement de cet objectif (sur la base de votre code) comme ceci, qui ouvre le fichier pour l'écriture. lecture :

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

Ouverture supposée pour la lecture

Pourquoi créer un répertoire pour un fichier dont on s'attend à ce qu'il soit là et qu'on puisse le lire ?

Essayez simplement d'ouvrir le fichier.

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

Si le répertoire ou le fichier n'est pas présent, vous obtiendrez un message d'erreur IOError avec un numéro d'erreur associé : errno.ENOENT indiquera le numéro d'erreur correct, quelle que soit votre plate-forme. Vous pouvez l'attraper si vous le souhaitez, 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 qu'on ouvre pour l'écriture

C'est probablement ce que vous voulez.

Dans ce cas, nous ne sommes probablement pas confrontés à des conditions de course. Faites donc comme avant, mais notez que pour l'écriture, vous devez ouvrir avec la commande w (ou a pour ajouter). C'est également 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 placer toutes leurs données dans le même répertoire. Dans ce cas, il peut y avoir conflit sur la création du répertoire. Dans ce cas, il est préférable d'envelopper la fonction makedirs dans un bloc try-except.

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)

44voto

Ali Afshar Points 22836

J'ai noté ce qui suit. Mais ce 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 l'ai dit, ce n'est pas vraiment infaillible, parce que nous avons la possibilité de ne pas créer le répertoire, et qu'un autre processus le crée pendant cette période.

35voto

Aaron Hall Points 7381

Vérifier si un répertoire existe et le 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 s'immiscent dans votre répertoire :

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

ou si la création du répertoire est sujette à des conditions de course (c'est-à-dire si après avoir vérifié que le chemin existe, quelque chose d'autre peut l'avoir déjà créé), faites ceci :

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

Mais une meilleure approche consiste peut-être à contourner le problème de contention des ressources en utilisant des répertoires temporaires par le biais de tempfile :

import tempfile

d = tempfile.mkdtemp()

Voici l'essentiel du document 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 dans Python 3.5 : pathlib.Path avec exist_ok

Il y a un nouveau Path (à partir de la version 3.4) avec de nombreuses méthodes que l'on peut utiliser avec les chemins - l'une d'entre elles est la suivante mkdir .

(Pour le contexte, je suis mon rep hebdomadaire avec un script. Voici les parties pertinentes du code du script qui me permettent d'éviter de frapper Stack Overflow 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 à faire face à os.path.join maintenant - il suffit de joindre les parties du chemin avec un / :

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

Ensuite, je m'assure de manière idempotente que le répertoire existe - la fonction exist_ok apparaît dans Python 3.5 :

directory.mkdir(exist_ok=True)

Voici la partie pertinente de l'article documentation :

Si exist_ok est vrai, FileExistsError les exceptions seront ignorées (même comportement que l'option POSIX mkdir -p ), mais seulement si le dernier composant du chemin d'accès n'est pas un fichier non répertorié existant.

Voici un peu plus du script - dans mon cas, je ne suis pas soumis à une condition de course, 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 essaie 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 contraints à str avant les autres API qui attendent str les chemins peuvent les utiliser.

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

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