检查文件目录是否存在的最优雅方法是什么,如果不存在,使用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)
是否有“开放”的标志,这会自动发生?
25 回答
使用try除了和errno模块的正确错误代码摆脱了竞争条件并且是跨平台的:
换句话说,我们尝试创建目录,但如果它们已经存在,我们会忽略错误 . 另一方面,报告任何其他错误 . 例如,如果您事先创建dir 'a'并从中删除所有权限,则会收到
OSError
,其中包含errno.EACCES
(权限被拒绝,错误13) .Python 3.5:
上面使用的pathlib.Path.mkdir以递归方式创建目录,如果目录已存在则不会引发异常 . 如果您不需要或不想创建父项,请跳过
parents
参数 .Python 3.2:
Using pathlib:
如果可以,请安装名为pathlib2的当前
pathlib
backport . 不要安装名为pathlib的旧的非维护后端口 . 接下来,请参阅上面的Python 3.5部分并使用它 .如果使用Python 3.4,即使它带有
pathlib
,它也缺少有用的exist_ok
选项 . backport旨在提供mkdir
的更新且更优越的实现,其中包括此缺失选项 .Using os:
上面使用的os.makedirs以递归方式创建目录,如果目录已存在则不会引发异常 . 它只有在使用Python 3.2时才有可选的
exist_ok
参数,默认值为False
. 这个参数在Python 2.x中不存在,最高可达2.7 . 因此,不需要像Python 2.7那样进行手动异常处理 .Python 2.7:
Using pathlib:
如果可以,请安装名为pathlib2的当前
pathlib
backport . 不要安装名为pathlib的旧的非维护后端口 . 接下来,请参阅上面的Python 3.5部分并使用它 .Using os:
虽然天真的解决方案可能首先使用os.path.isdir,然后使用os.makedirs,但上述解决方案会颠倒两个操作的顺序 . 这样做可以防止常见的竞争条件与创建目录的重复尝试有关,并且还可以消除目录中的文件歧义 .
请注意,捕获异常并使用
errno
的用处有限,因为对于文件和目录都会引发OSError: [Errno 17] File exists
,即errno.EEXIST
. 仅检查目录是否存在更可靠 .替代方案:
mkpath创建嵌套目录,如果该目录已存在则不执行任何操作 . 这适用于Python 2和3 .
根据Bug 10948,这种替代方案的一个严重限制是,对于给定路径,每个python进程只能运行一次 . 换句话说,如果您使用它来创建目录,然后从Python内部或外部删除目录,然后再次使用
mkpath
重新创建相同的目录,mkpath
将只是默默地使用其先前创建目录的无效缓存信息,并且实际上不会再次创建目录 . 相比之下,os.makedirs
不依赖于任何此类缓存 . 对于某些应用,此限制可能没问题 .关于目录的模式,如果您关心它,请参阅文档 .
在 Python3 中,
os.makedirs
支持设置exist_ok
. 默认设置为False
,这意味着如果目标目录已存在,则将引发OSError
. 通过将exist_ok
设置为True
,将忽略OSError
(目录存在),并且不会创建该目录 .在 Python2 中,
os.makedirs
不支持设置exist_ok
. 您可以使用heikki-toivonen's answer中的方法:我使用
os.path.exists()
,here是一个Python 3脚本,可用于检查目录是否存在,如果不存在则创建一个,如果存在则删除它(如果需要) .它会提示用户输入目录,并且可以轻松修改 .
您可以使用
os.listdir
:我看到了Heikki Toivonen和A-B-B的答案并想到了这种变化 .
在Python 3.4中,您还可以使用brand new pathlib module:
这将检查文件是否存在,如果不存在,那么它将创建它 .
我已经放下了以下内容 . 但这并非完全万无一失 .
现在正如我所说,这并非万无一失,因为我们有可能无法创建目录,而另一个进程在此期间创建它 .
检查os.makedirs :(确保存在完整路径 . )
要处理目录可能存在的事实,请捕获OSError . (如果exist_ok为False(默认值),则在目标目录已经引发OSError存在 . )
了解这种情况的具体情况
您在特定路径中提供特定文件,然后从文件路径中提取目录 . 然后在确保您拥有该目录后,尝试打开文件进行读取 . 要评论此代码:
我们希望避免覆盖内置函数
dir
. 另外,filepath
或者fullfilepath
可能是一个比filename
更好的语义名称,所以写得更好:你的最终目标是打开这个文件,你最初说,写,但你实际上是接近这个目标(基于你的代码),这样打开 reading 的文件:
假设开放阅读
为什么要为您希望在那里并且能够阅读的文件创建一个目录?
只是尝试打开文件 .
如果目录或文件不是't there, you' ll得到带有相关错误编号的
IOError
:errno.ENOENT
将指向正确的错误编号,无论您的平台如何 . 如果你愿意,你可以 grab 它,例如:假设我们正在写作
这可能就是你想要的 .
在这种情况下,我们可能没有遇到任何竞争条件 . 所以就像你一样,但请注意,对于写作,你需要打开
w
模式(或a
来追加) . 使用上下文管理器打开文件也是Python的最佳实践 .但是,假设我们有几个Python进程试图将所有数据放入同一目录中 . 然后我们可能会争论创建目录 . 在这种情况下,最好将
makedirs
调用包装在try-except块中 .使用文件I / O时,需要考虑的重要事项是
TOCTTOU(检查时间到使用时间)
因此,使用
if
进行检查然后稍后进行读取或写入可能会导致未处理的I / O异常 . 最好的方法是:我看到两个具有良好品质的答案,每个答案都有一个小缺陷,所以我会考虑它:
尝试os.path.exists,并考虑os.makedirs进行创建 .
正如评论和其他地方所述,存在竞争条件 - 如果在
os.path.exists
和os.makedirs
调用之间创建目录,os.makedirs
将失败并返回OSError
. 不幸的是,全面捕捉OSError
并继续并非万无一失,因为它会忽略由于其他因素(如权限不足,完整磁盘等)而无法创建目录 .一种选择是捕获
OSError
并检查嵌入的错误代码(请参阅Is there a cross-platform way of getting information from Python’s OSError):或者,可能会有第二个
os.path.exists
,但假设另一个在第一次检查后创建了目录,然后在第二次检查之前将其删除 - 我们仍然可能被愚弄 .根据应用程序,并发操作的危险可能多于或少于文件权限等其他因素造成的危险 . 在选择实现之前,开发人员必须更多地了解正在开发的特定应用程序及其预期环境 .
如果您考虑以下因素:
表示存在目录(路径)并且是目录 . 所以对我来说这样做是我需要的 . 所以我可以确保它是文件夹(不是文件)并且存在 .
我个人建议您使用
os.path.isdir()
来测试而不是os.path.exists()
.如果你有:
一个愚蠢的用户输入:
...如果使用
os.path.exists()
进行测试,当您将该参数传递给os.makedirs()
时,您最终会得到一个名为filename.etc
的目录 .如果在支持shell语言的机器上运行,为什么不使用子进程模块?适用于python 2.7和python 3.6
应该在大多数系统上做到这一点 .
试试os.path.exists功能
从Python 3.5开始,pathlib.Path.mkdir有一个
exist_ok
标志:这会以递归方式创建目录,如果目录已存在,则不会引发异常 .
(正如os.makedirs从python 3.2开始得到一个
exists_ok
标志) .我发现了这个Q / A,我最初对一些失败和错误感到困惑 . 我正在使用Python 3(在Arch Linux x86_64系统上的Anaconda虚拟环境中的v.3.5) .
考虑这个目录结构:
这是我的实验/笔记,它澄清了一些事情:
结论:在我看来,“方法2”更加健壮 .
[1] How can I create a directory if it does not exist?
[2] https://docs.python.org/3/library/os.html#os.makedirs
在程序/项目的入口点调用函数
create_dir()
.使用此命令检查并创建目录
relevant Python documentation建议使用EAFP coding style (Easier to Ask for Forgiveness than Permission) . 这意味着代码
比替代方案更好
文档建议这正是因为这个问题中讨论的竞争条件 . 另外,和其他人一样这里提到,在查询一次而不是两次操作系统时有一个性能优势 . 最后,在某些情况下,当开发人员知道应用程序正在运行的环境时,可能会提出有利于第二个代码的论点 - 只有在程序为其设置私有环境的特殊情况下才能提倡这个论点 . 本身(以及同一程序的其他实例) .
即使在这种情况下,这也是一种不好的做法,可能会导致长时间无用的调试 . 例如,我们为目录设置权限的事实不应该让我们为我们的目的设置适当的印象权限 . 可以使用其他权限挂载父目录 . 通常,程序应该始终正常工作,程序员不应该期望一个特定的环境 .
对此的直接回答是,假设您不希望其他用户或进程弄乱您的目录的简单情况:
or 如果使目录受到竞争条件的影响(即,如果在检查路径后存在,则可能还有其它东西)执行此操作:
但也许更好的方法是通过tempfile使用临时目录来回避资源争用问题:
以下是在线文档的基本要点:
该目录只有可读,可写和可搜索
创建用户 .
调用者负责在完成目录后删除目录 .
Python 3.5中的新功能:带有exist_ok的pathlib.Path
有一个新的
Path
对象(截至3.4),有许多方法需要与路径一起使用 - 其中一个是mkdir
.(对于上下文,我使用脚本跟踪我的每周代表 . 这是脚本中代码的相关部分,这些代码允许我避免每天多次针对相同数据访问Stack Overflow . )
首先是相关进口:
我们现在不必处理
os.path.join
- 只需使用/
连接路径部分:然后我自觉地确保目录存在 - 在Python 3.5中显示
exist_ok
参数:这是documentation的相关部分:
这里有一些脚本 - 在我的情况下,我不受竞争条件的限制,我只有一个进程需要目录(或包含文件),并且我没有任何东西试图删除目录 .
在期望
str
路径的其他API可以使用它们之前,必须将Path
个对象强制转换为str
.也许应该更新Pandas以接受抽象基类的实例
os.PathLike
.对于单线解决方案,您可以使用
IPython.utils.path.ensure_dir_exists()
:从documentation:确保目录存在 . 如果它不存在,尝试创建它并防止竞争条件,如果另一个进程正在做同样的事情 .
你可以用mkpath
请注意,它也将创建祖先目录 .
它适用于Python 2和3 .