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?
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.
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.
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).
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()
.
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
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)
à 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).
essayez la os.path.exists
fonction
if not os.path.exists(dir):
os.mkdir(dir)
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.
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 commandePOSIX 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
.
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.
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.
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.
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
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.
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é.
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.
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
vous pouvez utiliser os.listdir
pour ceci:
import os
if 'dirName' in os.listdir('parentFolderPath')
print('Directory Exists')
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
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.
utilisez cette commande vérifier et créer dir
if not os.path.isdir(test_img_dir):
os.mkdir(str("./"+test_img_dir))
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')
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.
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.