如何创建目录以及任何缺少的父目录?

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...

问题描述:

如何在给定路径上创建目录,并沿该路径创建任何缺少的父目录?例如,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.existsos.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 existserrno.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_okFalse(默认值),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.Pathexist_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。默认设置为FalseOSError即如果目标目录已存在,则会引发 。通过设置exist_okTrueOSError将忽略 (目录存在) 并且不会创建目录。

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:

这可能无法准确回答问题。但我猜你的真正意图是创建一个文件及其父目录,并在一个命令中给出其内容。

您可以使用fastcorepathlib 扩展来实现这一点:path.mk_write(data)

from fastcore.utils import Path
Path('/dir/to/file.txt').mk_write('Hello World')

更多内容请参阅fastcore 文档

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1265  
  IPD(Integrated Product Development)即集成产品开发,是一套先进的、成熟的产品开发管理理念、模式和方法。随着市场竞争的日益激烈,企业对于提升产品开发效率、降低成本、提高产品质量的需求愈发迫切,IPD 项目管理咨询市场也迎来了广阔的发展空间。深入探讨 IPD 项目管理咨询的市场需求与发展,...
IPD集成产品开发流程   17  
  IPD(Integrated Product Development)产品开发流程是一套先进的、被广泛应用的产品开发管理体系,它涵盖了从产品概念产生到产品推向市场并持续优化的全过程。通过将市场、研发、生产、销售等多个环节紧密整合,IPD旨在提高产品开发的效率、质量,降低成本,增强企业的市场竞争力。深入了解IPD产品开发...
IPD流程中TR   21  
  IPD(Integrated Product Development)测试流程是确保产品质量、提升研发效率的关键环节。它贯穿于产品从概念到上市的整个生命周期,对企业的成功至关重要。深入理解IPD测试流程的核心要点,有助于企业优化研发过程,打造更具竞争力的产品。以下将详细阐述IPD测试流程的三大核心要点。测试策略规划测试...
华为IPD   18  
  华为作为全球知名的科技企业,其成功背后的管理体系备受关注。IPD(集成产品开发)流程作为华为核心的产品开发管理模式,在创新管理与技术突破方面发挥了至关重要的作用。深入剖析华为 IPD 流程中的创新管理与技术突破,对于众多企业探索自身发展路径具有重要的借鉴意义。IPD 流程概述IPD 流程是一种先进的产品开发管理理念和方...
TR评审   16  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用