如何创建目录以及任何缺少的父目录?
- 2024-11-27 10:43:00
- admin 原创
- 175
问题描述:
如何在给定路径上创建目录,并沿该路径创建任何缺少的父目录?例如,Bash 命令mkdir -p /path/to/nested/directory
可以执行此操作。
解决方案 1:
在 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.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
(在 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.
解决方案 2:
Python 3.5+:
import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True)
pathlib.Path.mkdir
如上所述,递归创建目录,如果目录已存在,则不会引发异常。如果您不需要或不想创建父级,请跳过该parents
参数。
Python 3.2+:
使用pathlib
:
如果可以,请安装pathlib
名为 的当前反向移植版本pathlib2
。不要安装名为 的较旧且未维护的反向移植版本pathlib
。接下来,请参考上面的 Python 3.5+ 部分并以相同方式使用它。
如果使用 Python 3.4,即使它附带了pathlib
,也缺少有用的exist_ok
选项。反向移植旨在提供mkdir
包含此缺失选项的更新、更高级的实现。
使用os
:
import os
os.makedirs(path, exist_ok=True)
os.makedirs
如上所述,递归创建目录,如果目录已存在,则不会引发异常。exist_ok
只有在使用 Python 3.2+ 时,它才具有可选参数,默认值为False
。此参数在 Python 2.x 至 2.7 中不存在。因此,不需要像 Python 2.7 那样手动处理异常。
Python 2.7+:
使用pathlib
:
如果可以,请安装pathlib
名为 的当前反向移植版本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 和 Python 3 中均有效。但请注意,该功能distutils
已被弃用,并计划在 Python 3.12 中删除。
import distutils.dir_util
distutils.dir_util.mkpath(path)
根据Bug 10948,此替代方案的一个严重限制是,对于给定路径,它在每个 Python 进程中只能工作一次。换句话说,如果您使用它来创建目录,然后从 Python 内部或外部删除该目录,然后mkpath
再次使用它来重新创建同一个目录,mkpath
将只是默默地使用其之前创建目录的无效缓存信息,并且实际上不会再次创建目录。相反,os.makedirs
不依赖任何此类缓存。对于某些应用程序来说,这种限制可能没问题。
关于目录的模式,如果您关心的话,请参阅文档。
解决方案 3:
使用 try except 和来自 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”并从中删除所有权限,您将收到一个OSError
错误errno.EACCES
(权限被拒绝,错误 13)。
解决方案 4:
从 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)
这将递归创建目录,如果目录已经存在,则不会引发异常。
(就像从 python 3.2 开始os.makedirs
有一个标志一样)exist_ok
`os.makedirs(path, exist_ok=True)`
注意:当我发布这个答案时,其他答案都没有提到exist_ok
......
解决方案 5:
我个人建议您使用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
如果您有:
>>> directory = raw_input(":: ")
还有一个愚蠢的用户输入:
:: /tmp/dirname/filename.etc
...如果您使用 进行测试,那么您最终会得到一个名为 的目录filename.etc
,当您将该参数传递给 时。os.makedirs()
`os.path.exists()`
解决方案 6:
检查os.makedirs
:(确保完整路径存在。)
要处理目录可能存在的事实,请捕获OSError
。(如果exist_ok
是False
(默认值),OSError
则如果目标目录已存在,则会引发 。)
import os
try:
os.makedirs('./path/to/somewhere')
except OSError:
pass
解决方案 7:
尝试该os.path.exists
功能
if not os.path.exists(dir):
os.mkdir(dir)
解决方案 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:
我已记下以下内容。但它并非万无一失。
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
正如我所说,这并不是万无一失的,因为我们有可能无法创建目录,并且在此期间另一个进程会创建该目录。
解决方案 10:
检查目录是否存在,如有必要则创建它?
对此问题的直接回答是,假设一个简单的情况,您不希望其他用户或进程弄乱您的目录:
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'
然后我幂等地确保该目录存在 - 该exist_ok
参数显示在 Python 3.5 中:
directory.mkdir(exist_ok=True)
以下是文档的相关部分:
如果
exist_ok
为真,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))
Path
必须str
先将对象强制转换为路径,其他需要路径的 APIstr
才能使用它们。
也许应该更新 Pandas 以接受抽象基类的实例os.PathLike
。
解决方案 11:
最快最安全的方法是:如果不存在则创建,如果存在则跳过:
from pathlib import Path
Path("path/with/childs/.../").mkdir(parents=True, exist_ok=True)
解决方案 12:
import os
directory = "./out_dir/subdir1/subdir2"
if not os.path.exists(directory):
os.makedirs(directory)
解决方案 13:
在Python3中,os.makedirs
支持设置exist_ok
。默认设置为False
,OSError
即如果目标目录已存在,则会引发 。通过设置exist_ok
为True
,OSError
将忽略 (目录存在) 并且不会创建目录。
os.makedirs(path,exist_ok=True)
在Python2中,os.makedirs
不支持设置。您可以使用heikki-toivonen 的答案exist_ok
中的方法:
import os
import errno
def make_sure_path_exists(path):
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
解决方案 14:
在 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.
解决方案 15:
对于单行解决方案,您可以使用IPython.utils.path.ensure_dir_exists()
:
from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)
来自文档:确保目录存在。如果不存在,则尝试创建它,并防止另一个进程正在执行相同操作时出现竞争条件。
IPython 是一个扩展包,而不是标准库的一部分。
解决方案 16:
相关 Python 文档建议使用EAFP 编码风格(Easier to Ask for Forgiveness than Permission)。这意味着代码
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
else:
print "
BE CAREFUL! Directory %s already exists." % path
比其他选择更好
if not os.path.exists(path):
os.makedirs(path)
else:
print "
BE CAREFUL! Directory %s already exists." % path
文档正是由于这个问题中讨论的竞争条件而提出了这一点。此外,正如其他人在这里提到的那样,查询一次而不是两次操作系统具有性能优势。最后,在某些情况下(当开发人员知道应用程序正在运行的环境时),可能支持第二个代码的论点只能在程序为自己(以及同一程序的其他实例)设置了私有环境的特殊情况下才被提倡。
即使在这种情况下,这也是一种不好的做法,可能会导致长时间无用的调试。例如,我们为目录设置权限这一事实不应该让我们觉得权限设置适合我们的目的。父目录可以以其他权限挂载。一般来说,程序应该始终正常工作,程序员不应该期望一个特定的环境。
解决方案 17:
您可以将 exist_ok=True 参数传递给 os.makedirs() 函数,以在目录已存在的情况下抑制错误:
import os
# Create directory /path/to/nested/directory if it doesn't already exist
os.makedirs('/path/to/nested/directory', exist_ok=True)
解决方案 18:
在对使用 Python 目录时遇到的一些故障和错误感到困惑后,我找到了这个问答。我正在使用 Python 3(Arch Linux x86_64 系统上 Anaconda 虚拟环境中的 v.3.5)。
考虑以下目录结构:
└── output/ ## dir
├── corpus ## file
├── corpus2/ ## dir
└── subdir/ ## dir
这是我的实验/笔记,可以澄清一些问题:
# ----------------------------------------------------------------------------
# [1] https://stackoverflow.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
解决方案 19:
您可以使用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。
解决方案 20:
如果您将文件写入变量路径,则可以在文件路径上使用它来确保创建父目录。
from pathlib import Path
path_to_file = Path("zero/or/more/directories/file.ext")
parent_directory_of_file = path_to_file.parent
parent_directory_of_file.mkdir(parents=True, exist_ok=True)
即使path_to_file
深度file.ext
为零目录也可以工作。
参见pathlib.PurePath.parent和pathlib.Path.mkdir。
解决方案 21:
mkdir
如果在支持带选项的命令的机器上运行,为什么不使用子进程模块 -p
?适用于 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...
解决方案 22:
您必须在创建目录之前设置完整路径:
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)
这对我有用,希望对你也有用
解决方案 23:
我看到了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
解决方案 24:
我使用os.path.exists()
,这是一个 Python 3 脚本,可用于检查目录是否存在,如果不存在则创建一个,如果存在则删除它(如果需要)。
它提示用户输入目录,并且可以轻松修改。
解决方案 25:
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')
解决方案 26:
使用此命令检查并创建目录
if not os.path.isdir(test_img_dir):
os.mkdir(test_img_dir)
解决方案 27:
这可能无法准确回答问题。但我猜你的真正意图是创建一个文件及其父目录,并在一个命令中给出其内容。
您可以使用fastcore
pathlib 扩展来实现这一点:path.mk_write(data)
from fastcore.utils import Path
Path('/dir/to/file.txt').mk_write('Hello World')
更多内容请参阅fastcore 文档
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)