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




variable python (17)

Quel est le moyen le plus élégant de vérifier si le répertoire dans lequel un fichier va être écrit existe, et si ce n’est pas le cas, créez-le 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)

En quelque sorte, os.path.exists me manquait (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)

Existe-t-il un drapeau pour "ouvert", qui rend cela automatiquement?


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

La réponse directe à cela est, en supposant une situation simple où vous ne vous attendez pas à ce que d'autres utilisateurs ou processus se moquent de votre annuaire:

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

ou si la création du répertoire est soumise à des conditions de concurrence (c.-à-d. si, après avoir vérifié que le chemin d'accès existe, quelque chose d'autre l'a déjà fait), procédez comme suit:

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

Mais peut-être une meilleure solution consiste-t-elle à éviter le problème des conflits de ressources en utilisant des répertoires temporaires via 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 existe un nouvel objet Path (à partir de la version 3.4) avec de nombreuses méthodes que l’on voudrait utiliser avec des chemins, dont mkdir .

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

D'abord les importations pertinentes:

from pathlib import Path
import tempfile

Nous n'avons pas à nous os.path.join de os.path.join - il suffit de joindre des parties de chemin avec un / :

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

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

directory.mkdir(exist_ok=True)

Voici la partie pertinente de la pathlib.Path.mkdir :

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

Voici un peu plus de script - dans mon cas, je ne suis pas soumis à une condition de concurrence, je n'ai qu'un processus qui attend le répertoire (ou les fichiers contenus), et je n'ai rien à essayer 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 objets de Path doivent être forcés à str avant que les autres API qui s'attendent à ce qu'ils puissent les utiliser.

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


Insights sur les spécificités de cette situation

Vous donnez un fichier particulier à un certain chemin et vous extrayez le répertoire du chemin de fichier. Ensuite, après vous être assuré que vous avez le répertoire, vous essayez d'ouvrir un fichier en lecture. 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 . De plus, filepath ou fullfilepath est probablement un meilleur nom sémantique que filename , il serait donc 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 au départ, pour l’écriture, mais vous vous approchez essentiellement de cet objectif (en fonction de votre code) comme ceci, ce qui ouvre le fichier en lecture :

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

En supposant que l'ouverture pour la lecture

Pourquoi voudriez-vous créer un répertoire pour un fichier que vous espérez être là et que vous pourrez 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'existe pas, vous obtiendrez un IOError avec un numéro d'erreur associé: errno.ENOENT pointera sur 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 sommes ouverts à l'écriture

C'est probablement ce que vous voulez.

Dans ce cas, nous ne sommes probablement pas confrontés à des conditions de concurrence. Donc, faites comme vous étiez, mais notez que pour écrire, vous devez ouvrir avec le mode w (ou a pour ajouter). Il est également recommandé d'utiliser le gestionnaire de contexte pour ouvrir des fichiers en Python.

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

Cependant, supposons que plusieurs processus Python tentent de placer toutes leurs données dans le même répertoire. Ensuite, nous pouvons avoir une dispute sur la création du répertoire. Dans ce cas, il est préférable de makedirs appel 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)

À partir de Python 3.5, pathlib.Path.mkdir a un indicateur exist_ok :

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 le répertoire de manière récursive et ne génère pas d'exception si le répertoire existe déjà.

(juste comme os.makedirs eu un drapeau exists_ok partir de python 3.2).


En Python3 , os.makedirs prend en charge le paramètre exist_ok . Le paramètre par défaut est False , ce qui signifie qu'une OSError sera OSError si le répertoire cible existe déjà. En définissant exist_ok sur True , OSError (le répertoire existe) sera ignoré et le répertoire ne sera pas créé.

os.makedirs(path,exist_ok=True)

En Python2 , os.makedirs ne prend pas en charge le paramètre exist_ok . Vous pouvez utiliser l'approche dans la réponse de heikki-toivonen :

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 utilisant try except, le code d'erreur correct du module errno supprime la condition de concurrence critique et est multi-plateforme:

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 s'ils existent déjà, nous ignorons l'erreur. D'autre part, toute autre erreur est signalée. Par exemple, si vous créez au préalable un OSError 'a' et en supprimez toutes les autorisations, vous obtenez une OSError créée avec errno.EACCES (autorisation refusée, erreur 13).


Essayez la fonction os.path.exists

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

J'ai trouvé cette Q / A et j'étais initialement perplexe devant certains des échecs et des erreurs que je recevais. Je travaille dans Python 3 (v.3.5 dans un environnement virtuel Anaconda sur un système Arch Linux x86_64).

Considérons cette structure de répertoire:

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

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

# ----------------------------------------------------------------------------
# [1] https://.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 un répertoire s'il n'existe pas?

[2] os.makedirs


J'ai vu les réponses de Heikki Toivonen et share et j'ai pensé à cette variante.

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

Je recommanderais personnellement que vous os.path.isdir() pour tester à la place 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 tu as:

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

Et une entrée utilisateur stupide:

:: /tmp/dirname/filename.etc

... Vous allez vous retrouver avec un répertoire nommé filename.etc lorsque vous passerez cet argument à os.makedirs() si vous testez avec os.path.exists() .


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

Essayez os.path.exists et considérez os.makedirs pour la création.

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

Comme indiqué dans les commentaires et ailleurs, il existe une condition de os.path.exists : si le répertoire est créé entre les os.path.exists et os.makedirs , os.makedirs ci échouera avec une OSError . Malheureusement, poursuivre avec OSError couverture OSError n'est pas infaillible, car il OSError de la création du répertoire en raison d'autres facteurs, tels que des autorisations insuffisantes, un disque complet, etc.

Une option consisterait à OSError et à examiner le code d'erreur incorporé (voir Existe - t-il un moyen multiplate-forme d'obtenir des informations à partir de 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 deuxième os.path.exists , mais supposons qu'un autre ait créé le répertoire après le premier contrôle, puis l'a supprimé avant le second - nous pourrions toujours être dupes.

Selon l'application, le danger lié aux opérations simultanées peut être plus ou moins important que celui d'autres facteurs tels que les autorisations de fichiers. Avant de choisir une implémentation, le développeur devrait en savoir plus sur l'application en cours de développement et sur l'environnement attendu.


Pour une solution one-liner, vous pouvez utiliser IPython.utils.path.ensure_dir_exists() :

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

De la documentation : Assurez-vous qu'un répertoire existe. S'il n'existe pas, essayez de le créer et protégez-vous contre une situation de concurrence critique si un autre processus en fait de même.


Vérifiez os.makedirs : (Il s'assure que le chemin complet existe.)
Pour gérer le fait que le répertoire peut exister, récupérez OSError. (Si exist_ok est False (valeur par défaut), une erreur OSError est générée si le répertoire cible existe déjà.)

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

Lorsque vous travaillez avec des fichiers d'E / S, la chose importante à considérer est

TOCTTOU (heure de vérification à l'heure d'utilisation)

Donc, faire un test avec ifpuis lire ou écrire plus tard peut aboutir à une exception d'E / S non gérée. La meilleure façon de le faire est:

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

Si vous considérez ce qui suit:

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

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


Appelez 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')

Pourquoi ne pas utiliser le module de sous-processus s’il s’applique sur un ordinateur prenant en charge les 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.


import os
if os.path.isfile(filename):
    print "file exists"
else:
    "Your code here"

Où votre code ici est utilisez la commande (tactile)

Cela vérifiera si le fichier est là sinon il le créera.





operating-system