如何安全地创建嵌套目录?
检查文件目录是否存在的最优雅方法是什么?如果不存在,则使用Python创建目录? 这是我尝试过的:
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)
不知何故,我错过了os.path.exists
(感谢kanja,Blair和Douglas)。 这就是我现在所拥有的:
def ensure_dir(file_path):
directory = os.path.dirname(file_path)
if not os.path.exists(directory):
os.makedirs(directory)
是否有“打开”标志,使它自动发生?
#1楼
Python 3.5以上版本:
import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True)
pathlib.Path.mkdir
使用的pathlib.Path.mkdir
递归创建目录,如果目录已经存在,则不会引发异常。 如果不需要或不希望创建parents
,请跳过“ parents
参数。
Python 3.2以上版本:
使用pathlib
:
如果可以,请安装名为pathlib2
的当前pathlib
pathlib2
。 不要安装名为pathlib
的较旧的未维护的pathlib
。 接下来,请参考上面的Python 3.5+部分,并对其进行相同的使用。
如果使用Python 3.4,即使pathlib
附带了pathlib
,它也会缺少有用的exist_ok
选项。 反向端口旨在提供mkdir
的更新和更高级的实现,其中包括此缺少的选项。
使用os
:
import os
os.makedirs(path, exist_ok=True)
os.makedirs
使用的os.makedirs
递归创建目录,如果目录已经存在,则不会引发异常。 仅当使用Python 3.2+时,它才具有可选的exist_ok
参数,默认值为False
。 在2.7之前的Python 2.x中不存在此参数。 这样,就无需像Python 2.7那样进行手动异常处理。
Python 2.7+:
使用pathlib
:
如果可以,请安装名为pathlib2
的当前pathlib
pathlib2
。 不要安装名为pathlib
的较旧的未维护的pathlib
。 接下来,请参考上面的Python 3.5+部分,并对其进行相同的使用。
使用os
:
import os
try:
os.makedirs(path)
except OSError:
if not os.path.isdir(path):
raise
虽然幼稚的解决方案可能首先使用os.path.isdir
然后使用os.makedirs
,但是上述解决方案颠倒了这两个操作的顺序。 这样,它可以防止由于创建目录的重复尝试而导致的常见竞争情况,并且还可以消除目录中文件的歧义。
请注意,捕获异常并使用errno
的作用有限,因为OSError: [Errno 17] File exists
,即为文件和目录引发errno.EEXIST
。 仅检查目录是否存在更为可靠。
选择:
mkpath
创建嵌套目录,如果目录已经存在, mkpath
执行任何操作。 这适用于Python 2和3。
import distutils.dir_util
distutils.dir_util.mkpath(path)
根据Bug 10948 ,此替代方案的严重局限性在于,对于给定路径,每个python进程仅工作一次。 换句话说,如果使用它来创建目录,然后从Python内部或外部删除目录,然后再次使用mkpath
来重新创建同一目录,则mkpath
会简单地静默使用其先前已创建目录的无效缓存信息,并且实际上不会再次创建目录。 相反, os.makedirs
不依赖任何此类缓存。 对于某些应用程序,此限制可能是可以的。
关于目录的模式 ,如果您关心它,请参考文档。
#2楼
相关的Python文档建议使用EAFP编码样式(比许可更容易获得宽恕) 。 这意味着代码
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
else:
print "\nBE CAREFUL! Directory %s already exists." % path
比替代品更好
if not os.path.exists(path):
os.makedirs(path)
else:
print "\nBE CAREFUL! Directory %s already exists." % path
该文档正是由于此问题中讨论的种族条件而提出了这一建议。 此外,正如此处其他人所提到的,查询一次操作系统而不是两次查询操作系统具有性能优势。 最后,在某些情况下(当开发人员知道应用程序正在运行的环境时),可能会提出支持第二个代码的参数,只有在特殊情况下才提倡该程序已为该程序建立了私有环境。本身(以及同一程序的其他实例)。
即使在这种情况下,这也是一种不好的做法,并且可能导致长时间的无用调试。 例如,我们为目录设置权限的事实不应该使我们拥有为我们目的而适当设置的印象权限。 可以使用其他权限挂载父目录。 通常,程序应始终正常运行,并且程序员不应期望一个特定的环境。
#3楼
尝试os.path.exists
函数
if not os.path.exists(dir):
os.mkdir(dir)
#4楼
检查os.makedirs
:(确保存在完整路径。)
要处理目录可能存在的事实,请捕获OSError
。 (如果exist_ok
为False
(默认值),则在目标目录已存在的情况下引发OSError
。
import os
try:
os.makedirs('./path/to/somewhere')
except OSError:
pass
#5楼
我看到两个质量很好的答案,每个都有一个小缺陷,因此我将对此进行说明:
尝试os.path.exists
,并考虑使用os.makedirs
进行创建。
import os
if not os.path.exists(directory):
os.makedirs(directory)
如注释和其他地方所述,这是一个竞争条件–如果在os.path.exists
和os.makedirs
调用之间创建目录,则os.makedirs
将失败,并显示OSError
。 不幸的是,全面捕获OSError
并继续执行并非万无一失,因为它会忽略由于其他因素(例如权限不足,磁盘已满等)而导致的目录创建失败。
一种选择是捕获OSError
并检查嵌入式错误代码(请参阅是否存在从Python的OSError中获取信息的跨平台方法 ):
import os, errno
try:
os.makedirs(directory)
except OSError as e:
if e.errno != errno.EEXIST:
raise
另外,可能还有第二个os.path.exists
,但是假设另一个在第一次检查之后创建了目录,然后在第二次检查之前将其删除了–我们仍然可能会被愚弄。
根据应用程序的不同,并发操作的危险可能比其他因素(如文件许可权)造成的危险更大或更小。 在选择实现之前,开发人员必须了解有关正在开发的特定应用程序及其预期环境的更多信息。
现代版本的Python通过暴露FileExistsError
(在FileExistsError
版本中)都FileExistsError
改善了此代码。
try:
os.makedirs("path/to/directory")
except FileExistsError:
# directory already exists
pass
...,并允许os.makedirs
的关键字参数称为exist_ok
(在3.2+中)。
os.makedirs("path/to/directory", exist_ok=True) # succeeds even if directory exists.
#6楼
我将以下内容放下。 但是,这并非完全安全。
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
现在,正如我所说,这并不是万无一失的,因为我们有可能无法创建目录,而在此期间可能会有另一个进程创建目录。
#7楼
检查目录是否存在并根据需要创建目录?
对此的直接答案是,假设有一个简单的情况,您不希望其他用户或进程弄乱您的目录:
if not os.path.exists(d):
os.makedirs(d)
或者如果使目录符合竞争条件(即如果检查路径是否存在,则可能已经建立了其他路径),请执行以下操作:
import errno
try:
os.makedirs(d)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
但是,也许更好的方法是通过tempfile
使用临时目录来避免资源争用问题:
import tempfile
d = tempfile.mkdtemp()
以下是在线文档中的要点:
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.
新的Python 3.5: pathlib.Path
与exist_ok
有一个新的Path
对象(从3.4版本开始),它具有许多要与路径一起使用的方法-其中之一是mkdir
。
(对于上下文,我正在使用脚本跟踪我的每周代表。这是脚本中的代码的相关部分,这些内容使我避免对同一数据每天多次遇到Stack Overflow。)
首先是相关进口:
from pathlib import Path
import tempfile
我们现在不必处理os.path.join
只需使用/
连接路径部分:
directory = Path(tempfile.gettempdir()) / 'sodata'
然后,我确定地确保目录存在-在Python 3.5中显示了exist_ok
参数:
directory.mkdir(exist_ok=True)
这是文档的相关部分:
如果
exist_ok
为true,FileExistsError
仅当最后一个路径组件不是现有的非目录文件时,才会忽略FileExistsError
异常(与POSIX mkdir -p
命令相同的行为)。
这里还有更多脚本-就我而言,我不受竞争条件的影响,我只有一个进程希望目录(或包含的文件)存在,并且我没有任何尝试删除的过程目录。
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))
在其他期望str
路径可以使用它们的API之前,必须将Path
对象强制转换为str
。
也许应该更新Pandas以接受抽象基类os.PathLike
。
#8楼
对这种情况的具体见解
您在特定路径下提供特定文件,然后从文件路径中提取目录。 然后,在确保您拥有目录之后,尝试打开一个文件进行读取。 要对此代码发表评论:
filename = "/my/directory/filename.txt" dir = os.path.dirname(filename)
我们要避免覆盖内置函数dir
。 此外, filepath
或者是fullfilepath
可能是一个更好的语义的名称不是filename
等等,这将更好的写法:
import os
filepath = '/my/directory/filename.txt'
directory = os.path.dirname(filepath)
您的最终目标是打开该文件,一开始就声明要写入,但实际上您正在达到这个目标(基于您的代码),就像这样,打开文件进行读取 :
if not os.path.exists(directory): os.makedirs(directory) f = file(filename)
假设开放阅读
为什么要为您希望存在并能够读取的文件创建目录?
只是尝试打开文件。
with open(filepath) as my_file:
do_stuff(my_file)
如果目录或文件不存在,您将得到一个带有相关错误号的IOError
: errno.ENOENT
将指向正确的错误号,而不管您的平台如何。 您可以根据需要捕获它,例如:
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
假设我们正在写作
这可能就是您想要的。
在这种情况下,我们可能没有面对任何比赛条件。 因此,只要做你是,但要注意,对于写作,你需要用开w
模式(或a
附加)。 使用上下文管理器打开文件也是Python的最佳实践。
import os
if not os.path.exists(directory):
os.makedirs(directory)
with open(filepath, 'w') as my_file:
do_stuff(my_file)
但是,假设我们有几个Python进程试图将其所有数据放入同一目录。 然后,我们可能会争执目录的创建。 在这种情况下,最好将makedirs
调用包装在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)
#9楼
在Python 3.4中,您还可以使用全新的pathlib
模块 :
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.
#10楼
我看到了Heikki Toivonen和ABB的答案,并想到了这种变化。
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
#11楼
对于IPython.utils.path.ensure_dir_exists()
解决方案,可以使用IPython.utils.path.ensure_dir_exists()
:
from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)
从文档中 : 确保目录存在。 如果不存在,请尝试创建它,并在其他进程正在这样做的情况下防止出现竞争情况。
#12楼
您可以为此使用os.listdir
:
import os
if 'dirName' in os.listdir('parentFolderPath')
print('Directory Exists')
#13楼
您可以使用mkpath
# Create a directory and any missing ancestor directories.
# If the directory already exists, do nothing.
from distutils.dir_util import mkpath
mkpath("test")
请注意,它也会创建祖先目录。
它适用于Python 2和3。
#14楼
如果考虑以下因素:
os.path.isdir('/tmp/dirname')
表示目录(路径)存在,并且是目录。 所以对我来说,这种方式满足了我的需求。 因此,我可以确保它是文件夹(不是文件)并且存在。
#15楼
从Python 3.5开始, pathlib.Path.mkdir
具有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)
这将以递归方式创建目录,并且如果目录已经存在,则不会引发异常。
(就像os.makedirs
从python 3.2开始有一个exist_ok
标志一样,例如os.makedirs(path, exist_ok=True)
))
#16楼
在Python3中 , os.makedirs
支持设置exist_ok
。 默认设置为False
,这意味着如果目标目录已经存在,则会引发OSError
。 通过将exist_ok
设置为True
,将忽略OSError
(目录存在),并且不会创建目录。
os.makedirs(path,exist_ok=True)
在Python2中 , os.makedirs
不支持设置exist_ok
。 您可以在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
#17楼
我使用os.path.exists()
, 这是一个Python 3脚本,可用于检查目录是否存在,如果不存在则创建一个目录,如果存在则将其删除(如果需要)。
它提示用户输入目录,并且可以轻松修改。
#18楼
我个人建议您使用os.path.isdir()
来测试,而不是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
如果你有:
>>> dir = raw_input(":: ")
和愚蠢的用户输入:
:: /tmp/dirname/filename.etc
...如果使用os.path.exists()
测试,则将该参数传递给os.makedirs()
时,将以一个名为filename.etc
的目录结尾。
#19楼
import os
if os.path.isfile(filename):
print "file exists"
else:
"Your code here"
您的代码在哪里使用(touch)命令
这将检查文件是否存在,如果不存在则将创建它。
#20楼
我找到了这个问题,起初我为自己遇到的一些失败和错误感到困惑。 我正在使用Python 3(在Arch Linux x86_64系统上的Anaconda虚拟环境中的v.3.5中)中工作。
考虑以下目录结构:
└── output/ ## dir
├── corpus ## file
├── corpus2/ ## dir
└── subdir/ ## dir
这是我的实验/注释,它们使事情变得清晰:
# ----------------------------------------------------------------------------
# [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
# ----------------------------------------------------------------------------
结论:我认为“方法2”更可靠。
[1] 如果目录不存在,如何创建?
[2] https://docs.python.org/3/library/os.html#os.makedirs
#21楼
使用此命令检查并创建目录
if not os.path.isdir(test_img_dir):
os.mkdir(test_img_dir)
#22楼
在程序/项目的入口点调用函数create_dir()
。
import os
def create_dir(directory):
if not os.path.exists(directory):
print('Creating Directory '+directory)
os.makedirs(directory)
create_dir('Project directory')
#23楼
使用tryexcept和来自errno模块的正确错误代码摆脱了竞争条件,并且是跨平台的:
import os
import errno
def make_sure_path_exists(path):
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
换句话说,我们尝试创建目录,但是如果它们已经存在,我们将忽略该错误。 另一方面,将报告任何其他错误。 例如,如果您预先创建目录'a'并从中删除所有权限,则将出现errno.EACCES
引发OSError
(权限被拒绝,错误13)。
#24楼
如果在支持带有-p
选项的命令mkdir
的计算机上运行,为什么不使用子进程模块? 适用于python 2.7和python 3.6
from subprocess import call
call(['mkdir', '-p', 'path1/path2/path3'])
在大多数系统上都可以做到。
在可移植性无关紧要的情况下(例如,使用docker),解决方案只需2行。 您也不必添加逻辑来检查目录是否存在。 最后,重新运行很安全,没有任何副作用
如果您需要错误处理:
from subprocess import check_call
try:
check_call(['mkdir', '-p', 'path1/path2/path3'])
except:
handle...
#25楼
您必须在创建目录之前设置完整路径:
import os,sys,inspect
import pathlib
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
your_folder = currentdir + "/" + "your_folder"
if not os.path.exists(your_folder):
pathlib.Path(your_folder).mkdir(parents=True, exist_ok=True)
这对我有用,希望对您也一样
上一篇: Handlebars 模板引擎,及在 node 项目中使用
下一篇: Spring Security