如何安全地创建嵌套目录?

新手上路,请多包涵

如何检查要写入文件的目录是否存在,如果不存在,则使用 Python 创建目录?

原文由 Parand 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 706
2 个回答

在 Python ≥ 3.5 上,使用 pathlib.Path.mkdir

 from pathlib import Path
Path("/my/directory").mkdir(parents=True, exist_ok=True)

对于旧版本的 Python,我看到两个质量很好的答案,每个都有一个小缺陷,所以我会给出我的看法:

尝试 os.path.exists ,并考虑 os.makedirs 进行创建。

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

如评论和其他地方所述,存在竞争条件 - 如果在 os.path.existsos.makedirs 调用之间创建目录,则 os.makedirs 将失败并显示 OSError 。不幸的是,一揽子 OSError 并继续不是万无一失的,因为它会忽略由于其他因素(例如权限不足、磁盘已满等)创建目录失败。

一种选择是捕获 OSError 并检查嵌入的错误代码(请参阅 Is there a cross-platform way of getting information from Python’s OSError ):

 import os, errno

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

或者,可能有第二个 os.path.exists ,但假设另一个在第一次检查之后创建了目录,然后在第二次检查之前将其删除 - 我们仍然可能被愚弄。

根据应用程序的不同,并发操作的危险可能大于或小于文件权限等其他因素带来的危险。在选择实现之前,开发人员必须更多地了解正在开发的特定应用程序及其预期环境。

现代版本的 Python 通过公开 FileExistsError (在 3.3+ 中)对这段代码进行了相当大的改进…

 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.

原文由 Blair Conrad 发布,翻译遵循 CC BY-SA 4.0 许可协议

Python 3.5+:

 import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True)

pathlib.Path.mkdir 如上所用递归创建目录,如果目录已经存在则不会引发异常。如果您不需要或不希望创建父母,请跳过 parents 参数。

Python 3.2+:

使用 pathlib

如果可以,请安装名为 pathlib2 的当前 pathlib backport。不要安装名为 pathlib 的旧的未维护的反向端口。接下来参考上面的Python 3.5+部分,照样使用。

如果使用 Python 3.4,即使它带有 pathlib ,它也缺少有用的 exist_ok 选项。向后移植旨在提供 mkdir 的更新和更好的实现,其中包括这个缺失的选项。

使用 os

 import os
os.makedirs(path, exist_ok=True)

os.makedirs 如上所用递归创建目录,如果目录已经存在则不会引发异常。只有在使用 Python 3.2+ 时,它才有可选的 exist_ok 参数,默认值为 False 。此参数在 Python 2.x 到 2.7 之前不存在。因此,不需要像 Python 2.7 那样进行手动异常处理。

Python 2.7+:

使用 pathlib

如果可以,安装当前的 pathlib backport 名为 pathlib2 。不要安装名为 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 创建嵌套目录,如果目录已经存在,则不执行任何操作。这适用于 Python 2 和 3。

 import distutils.dir_util
distutils.dir_util.mkpath(path)

根据 Bug 10948 ,此替代方案的一个严重限制是它对给定路径的每个 python 进程只能工作一次。换句话说,如果您使用它创建一个目录,然后从 Python 内部或外部删除该目录,然后再次使用 mkpath 重新创建相同的目录, mkpath 将简单地静默使用它先前创建目录的无效缓存信息,实际上不会再次创建该目录。相反, os.makedirs 不依赖任何此类缓存。对于某些应用程序,此限制可能没问题。


关于目录的 _模式_,如果你关心它,请参考文档。

原文由 Asclepius 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题