提问人:Parand 提问时间:11/8/2008 最后编辑:Mateen UlhaqParand 更新时间:5/1/2023 访问量:3622481
如何创建目录以及任何缺少的父目录?
How do I create a directory, and any missing parent directories?
问:
如何在给定路径上创建目录,并沿该路径创建任何缺少的父目录?例如,Bash 命令就是这样做的。mkdir -p /path/to/nested/directory
答:
尝试使用 os.path.exists
函数
if not os.path.exists(dir):
os.mkdir(dir)
评论
FileNotFoundError
。os.mkdir
检查 os.makedirs
:(确保完整路径存在。
要处理目录可能存在的事实,请捕获 .
(如果为 is(默认值),则在目标目录已存在时引发 an。OSError
exist_ok
False
OSError
import os
try:
os.makedirs('./path/to/somewhere')
except OSError:
pass
评论
在 Python ≥ 3.5 上,使用 pathlib。路径.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
一种选择是捕获并检查嵌入的错误代码(请参阅是否有从 Python 的 OSError 获取信息的跨平台方法):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.
评论
os.path.exists
也返回文件。我已经发布了一个答案来解决这个问题。True
exists_ok
os.makedirs()
os.mkdirs()
如果意外遗漏了路径分隔符,当前文件夹与预期不符,则路径元素包含路径分隔符,则可以创建意外的文件夹。如果您使用这些错误,将引发异常,提醒您它们的存在。os.mkdir()
我把以下内容写下来。不过,这并不是完全万无一失的。
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
现在,正如我所说,这并不是万无一失的,因为我们有可能无法创建目录,并且在此期间有另一个进程创建它。
我个人建议你用 to test 而不是 .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()
使用 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”并从中删除了所有权限,则将收到 (权限被拒绝,错误 13) 。OSError
errno.EACCES
评论
exception.errno != errno.EEXIST
os.makedirs(path,exist_ok=True)
exist_ok
蟒蛇 3.5+:
import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True)
pathlib 中。上面使用的 Path.mkdir
以递归方式创建目录,如果目录已存在,则不会引发异常。如果不需要或不希望创建父级,请跳过参数。parents
蟒蛇 3.2+:
使用 pathlib
:
如果可以,请安装当前名为 pathlib2
的向后移植。不要安装名为 pathlib
的旧未维护的后向后端口。接下来,请参阅上面的 Python 3.5+ 部分并使用它。pathlib
如果使用 Python 3.4,即使它附带了 ,它也缺少有用的选项。向后移植旨在提供更新和更好的实现,其中包括这个缺失的选项。pathlib
exist_ok
mkdir
使用操作系统
:
import os
os.makedirs(path, exist_ok=True)
上面使用的 os.makedirs
以递归方式创建目录,如果目录已存在,则不会引发异常。仅当使用 Python 3.2+ 时,它才具有可选参数,默认值为 。Python 2.x 到 2.7 中不存在此参数。因此,不需要像 Python 2.7 那样手动处理异常。exist_ok
False
蟒蛇 2.7+:
使用 pathlib
:
如果可以,请安装当前名为 pathlib2
的向后移植。不要安装名为 pathlib
的旧未维护的后向后端口。接下来,请参阅上面的 Python 3.5+ 部分并使用它。pathlib
使用操作系统
:
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。但请注意,distutils
已被弃用,并计划在 Python 3.12 中删除。
import distutils.dir_util
distutils.dir_util.mkpath(path)
根据 Bug 10948,此替代方案的严重限制是它对给定路径的每个 python 进程仅工作一次。换句话说,如果你用它来创建一个目录,然后从 Python 内部或外部删除该目录,然后再次使用重新创建同一个目录,将只是静默地使用其之前创建过该目录的无效缓存信息,并且不会实际再次创建该目录。相比之下,不依赖于任何此类缓存。对于某些应用程序,此限制可能没问题。mkpath
mkpath
os.makedirs
关于目录的模式,如果您关心它,请参阅文档。
评论
os.path.isdir
相关的 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
文档之所以建议这样做,正是因为这个问题中讨论的竞争条件。此外,正如其他人在这里提到的,查询一次而不是两次操作系统具有性能优势。最后,在某些情况下,当开发人员知道应用程序正在运行的环境时,可能支持第二种代码的论点只能在程序为自己(以及同一程序的其他实例)设置私有环境的特殊情况下才能得到提倡。
即使在这种情况下,这也是一种不好的做法,并可能导致长时间无用的调试。例如,我们为目录设置权限的事实不应该给我们留下印象,权限是为我们的目的而设置的。可以使用其他权限挂载父目录。一般来说,程序应该始终正常工作,程序员不应该期望一个特定的环境。
检查目录是否存在并在必要时创建它?
对此的直接答案是,假设一个简单的情况,即您不希望其他用户或进程弄乱您的目录:
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
但也许更好的方法是通过临时文件使用临时
目录来回避资源争用问题:
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
有一个新对象(从 3.4 开始),其中包含许多想要用于路径的方法 - 其中之一是 .Path
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)
以下是文档的相关部分:
如果为 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
必须先强制对象,然后其他期望路径的 API 才能使用它们。str
str
也许应该更新 Pandas 以接受抽象基类的实例。os.PathLike
对这种情况的具体情况的见解
在特定路径上提供特定文件,然后从文件路径中提取目录。然后,在确保拥有目录后,尝试打开文件进行读取。要对此代码进行注释,请执行以下操作:
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
假设我们正在开放写作
这可能就是你想要的。
在这种情况下,我们可能没有面临任何竞争条件。所以就照原样做吧,但请注意,对于写作,你需要用模式打开(或附加)。使用上下文管理器打开文件也是一种 Python 最佳实践。w
a
import os
if not os.path.exists(directory):
os.makedirs(directory)
with open(filepath, 'w') as my_file:
do_stuff(my_file)
但是,假设我们有几个 Python 进程试图将其所有数据放入同一目录中。然后,我们可能会对目录的创建产生争执。在这种情况下,最好将调用包装在 try-except 块中。makedirs
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)
在 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.
我看到了Heikki Toivonen和A-B-B的回答,并想到了这种变化。
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
对于单行解决方案,可以使用 IPython.utils.path.ensure_dir_exists()
:
from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)
来自文档:确保目录存在。如果它不存在,请尝试创建它,并在另一个进程正在执行相同操作时防止出现争用条件。
IPython 是一个扩展包,不是标准库的一部分。
你可以使用 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。
从 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)
)
注意:当我发布此答案时,其他答案都没有提到......exist_ok
评论
在 Python3 中,支持设置 .默认设置为 ,这意味着如果目标目录已存在,将引发 。设置为 ,(目录存在)将被忽略,并且不会创建该目录。os.makedirs
exist_ok
False
OSError
exist_ok
True
OSError
os.makedirs(path,exist_ok=True)
在 Python2 中,不支持设置 .您可以在 heikki-toivonen 的回答中使用这种方法:os.makedirs
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
我使用 ,这是一个 Python 3 脚本,可用于检查目录是否存在,如果目录不存在,则创建一个目录,如果目录存在,则将其删除(如果需要)。os.path.exists()
它提示用户输入目录,并且可以轻松修改。
评论
在我对在 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
评论
使用此命令检查并创建目录
if not os.path.isdir(test_img_dir):
os.mkdir(test_img_dir)
评论
FileNotFoundError
。os.mkdir
在程序/项目的入口点调用该函数。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')
如果在支持带选项命令的机器上运行,为什么不使用子进程模块?
适用于 python 2.7 和 python 3.6mkdir
-p
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...
在创建目录之前,必须设置完整路径:
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)
这对我有用,希望它也对你有用
这可能并不能完全回答这个问题。但我想你的真正意图是创建一个文件及其父目录,因为它的内容都在一个命令中。
你可以通过扩展 pathlib 来做到这一点:fastcore
path.mk_write(data)
from fastcore.utils import Path
Path('/dir/to/file.txt').mk_write('Hello World')
在 fastcore 文档中查看更多信息
如果要将文件写入变量路径,则可以在文件的路径上使用它来确保创建父目录。
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)
即使 is(零目录深度)也有效。path_to_file
file.ext
请参阅 pathlib。PurePath.parent 和 pathlib。路径.mkdir。
import os
directory = "./out_dir/subdir1/subdir2"
if not os.path.exists(directory):
os.makedirs(directory)
最快最安全的方法是: 如果不存在,它将创建,如果存在,它将跳过:
from pathlib import Path
Path("path/with/childs/.../").mkdir(parents=True, exist_ok=True)
您可以将 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)
评论
上一个:如何执行程序或调用系统命令?
下一个:在“for”循环中访问索引
评论
p
os.makedirs(p[:p.rindex(os.path.sep)], exist_ok=True)