如何检查要写入文件的目录是否存在,如果不存在,则使用 Python 创建目录?
p
的父目录,这里是我的代码片段:os.makedirs(p[:p.rindex(os.path.sep)], exist_ok=True)
在 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
并检查嵌入的错误代码(请参阅 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
...并通过允许 a keyword argument to os.makedirs
called exist_ok
(在 3.2+ 中)。
os.makedirs("path/to/directory", exist_ok=True) # succeeds even if directory exists.
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
反向端口。不要安装名为 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
:
如果可以,请安装名为 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
创建嵌套目录,如果该目录已存在,则不执行任何操作。这适用于 Python 2 和 3。
import distutils.dir_util
distutils.dir_util.mkpath(path)
根据 Bug 10948,此替代方案的一个严重限制是它对于给定路径的每个 python 进程仅工作一次。换句话说,如果您使用它创建一个目录,然后从 Python 内部或外部删除该目录,然后再次使用 mkpath
重新创建相同的目录,mkpath
将简单地使用其先前创建的无效缓存信息目录,并且实际上不会再次创建该目录。相反,os.makedirs
不依赖任何此类缓存。对于某些应用程序,此限制可能没问题。
关于目录的模式,如果你关心,请参考文档。
os.path.isdir
之间其他人删除了该文件夹,您将引发该文件夹存在的错误、过时和令人困惑的错误。
使用 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
换句话说,我们尝试创建目录,但如果它们已经存在,我们将忽略错误。另一方面,报告任何其他错误。例如,如果您事先创建 dir 'a' 并从中删除所有权限,您将收到一个 errno.EACCES
引发的 OSError
(权限被拒绝,错误 13)。
exception.errno != errno.EEXIST
会无意中忽略路径存在但为非目录对象(例如文件)时的情况,才引发异常。如果路径是非目录对象,则理想情况下应该引发异常。
os.makedirs(path,exist_ok=True)
exist_ok
参数是在 Python 3.2 中引入的。它在 Python 2.x 中不存在。我会将其纳入我的答案中。
从 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
...
我个人建议您使用 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
的目录。
检查 os.makedirs
:(它确保完整路径存在。)
要处理目录可能存在的事实,请捕获 OSError
。 (如果 exist_ok
是 False
(默认值),如果目标目录已经存在,则会引发 OSError
。)
import os
try:
os.makedirs('./path/to/somewhere')
except OSError:
pass
关于这种情况的具体情况的见解
您在特定路径中提供特定文件,然后从文件路径中提取目录。然后在确保您拥有该目录之后,您尝试打开一个文件进行读取。要评论此代码:
文件名 = "/my/directory/filename.txt" 目录 = os.path.dirname(文件名)
我们希望避免覆盖内置函数 dir
。此外,filepath
或 fullfilepath
可能是比 filename
更好的语义名称,所以这样写会更好:
import os
filepath = '/my/directory/filename.txt'
directory = os.path.dirname(filepath)
你的最终目标是打开这个文件,你最初声明,写,但你基本上是这样接近这个目标(基于你的代码),它打开文件进行阅读:
如果不是 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)
我已经把以下内容。不过,这也不是万无一失的。
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
现在正如我所说,这并不是万无一失的,因为我们有可能无法创建目录,并且在此期间有另一个进程创建它。
检查目录是否存在并在必要时创建它?
对此的直接答案是,假设您不希望其他用户或进程弄乱您的目录的简单情况:
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) 用户可调用函数,用于创建并返回唯一的临时目录。返回值是目录的路径名。该目录只能由创建用户读取、写入和搜索。调用者负责在完成后删除目录。
Python 3.5 中的新功能:pathlib.Path 和 exists_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)
以下是 documentation 的相关部分:
如果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
,然后其他需要 str
路径的 API 才能使用它们。
也许应该更新 Pandas 以接受抽象基类 os.PathLike
的实例。
在 Python 3.4 中,您还可以使用 brand new pathlib
module:
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.
对于单行解决方案,您可以使用 IPython.utils.path.ensure_dir_exists()
:
from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)
从 documentation:确保目录存在。如果它不存在,请尝试创建它并在另一个进程正在执行相同操作时防止出现竞争条件。
IPython 是一个扩展包,不是标准库的一部分。
在 Python3 中,os.makedirs
支持设置 exist_ok
。默认设置为 False
,这意味着如果目标目录已经存在,则会引发 OSError
。通过将 exist_ok
设置为 True
,将忽略 OSError
(目录存在)并且不会创建目录。
os.makedirs(path,exist_ok=True)
在 Python2 中,os.makedirs
不支持设置 exist_ok
。您可以使用 heikki-toivonen's answer 中的方法:
import os
import errno
def make_sure_path_exists(path):
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
relevant Python documentation 建议使用 EAFP coding style (Easier to Ask for Forgiveness than Permission)。这意味着代码
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
文档表明这一点正是因为这个问题中讨论的竞争条件。此外,正如其他人在这里提到的那样,查询一次而不是两次操作系统具有性能优势。最后,在某些情况下可能支持第二个代码的论点——当开发人员知道应用程序正在运行的环境时——只能在程序设置了私有环境的特殊情况下被提倡。本身(以及同一程序的其他实例)。
即使在这种情况下,这也是一种不好的做法,并且可能导致长时间无用的调试。例如,我们为目录设置权限这一事实不应该给我们留下印象权限是为我们的目的而适当设置的。可以使用其他权限安装父目录。一般来说,一个程序应该总是正确地工作,程序员不应该期望一个特定的环境。
在 python 中执行此操作的最佳方法
#Devil
import os
directory = "./out_dir/subdir1/subdir2"
if not os.path.exists(directory):
os.makedirs(directory)
在我对在 Python 中使用目录时遇到的一些失败和错误感到困惑之后,我发现了这个 Q/A。我正在使用 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] How can I safely create a nested directory?
[2] https://docs.python.org/3/library/os.html#os.makedirs
最快最安全的方法是:如果不存在则创建,如果存在则跳过:
from pathlib import Path
Path("path/with/childs/.../").mkdir(parents=True, exist_ok=True)
您可以使用 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。
如果在支持命令 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...
您必须在创建目录之前设置完整路径:
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)
这对我有用,希望它也对你有用
如果您将文件写入变量路径,您可以在文件路径上使用它来确保创建父目录。
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。
我看到 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
我使用 os.path.exists()
,here 是一个 Python 3 脚本,可用于检查目录是否存在,如果不存在则创建一个,如果存在则删除它(如果需要)。
它提示用户输入目录并且可以很容易地修改。
使用此命令检查并创建目录
if not os.path.isdir(test_img_dir):
os.mkdir(test_img_dir)
在程序/项目的入口点调用函数 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')
如果您考虑以下情况:
os.path.isdir('/tmp/dirname')
表示存在目录(路径)并且是目录。所以对我来说,这种方式可以满足我的需要。所以我可以确保它是文件夹(不是文件)并且存在。
您可以为此使用 os.listdir
:
import os
if 'dirName' in os.listdir('parentFolderPath')
print('Directory Exists')
这可能不能完全回答这个问题。但我猜你的真正意图是创建一个文件及其父目录,因为它的内容全部在 1 个命令中。
您可以使用 pathlib 的 fastcore
扩展来做到这一点:path.mk_write(data)
from fastcore.utils import Path
Path('/dir/to/file.txt').mk_write('Hello World')
在 fastcore documentation 中查看更多信息
您可以使用系统调用创建嵌套目录 dir1/dir2/...
。说在Linux下可以这样做:
import os
dirs='dir1/dir2/dir3'
os.system("mkdir -p {0}".format(dirs))
标志 -p
检查目录是否存在,在这种情况下不会生成任何错误消息。
让我提一下,这看起来不像是完全由 Python 方法完成的,任何做同样事情的 Python 库都应该在内部使用上述类型的系统调用。
不定期副业成功案例分享
os.path.exists
还为文件返回True
。我已经发布了一个答案来解决这个问题。os.makedirs()
的exists_ok
参数可用于涵盖如何处理路径的先前存在。os.mkdirs()
可能会创建意外文件夹,当前文件夹与预期不符,路径元素包含路径分隔符。如果您使用os.mkdir()
,这些错误将引发异常,提醒您它们的存在。