【问题标题】:How to delete a directory created with tempfile.mkdtemp?如何删除使用 tempfile.mkdtemp 创建的目录?
【发布时间】:2011-07-30 18:02:21
【问题描述】:

我有一个 python 程序,它使用tempfile.mkdtemp/temp 下创建临时目录。不幸的是,Python程序在使用后并没有删除该目录。所以现在磁盘空间不足。

问题:

  1. 如何手动删除/temp下的临时目录?我尝试手动删除它们,但出现“权限被拒绝”错误。
  2. 在Python程序中,temp目录使用后如何删除?

【问题讨论】:

  • 我认为 OP 的问题没有被理解。建议的代码是一个很好的例子,说明您应该在程序中编写什么来清除创建的临时目录。但是,如果您的应用程序崩溃(硬)而没有机会运行该清理代码怎么办?然后你会有一个临时目录,只能由创建它的原始进程删除(至少文档似乎表明)——应该如何清理它?
  • 您是否尝试使用 root 帐户/管理员?
  • 关于1(手动删除):是权限问题:修复权限并删除,例如:chmod -R +w /tmp/tmp0ytcxm9c && rm -fr /tmp/tmp0ytcxm9c(如果是权限错误,你需要是运行程序的用户,或根)。

标签: python linux


【解决方案1】:

要在 Python 中管理资源(如文件),最佳实践是使用 @987654321@ 关键字,它会自动释放资源(即清理,如关闭文件);这在 Python 2.5 中可用。

从 Python 3.2 开始,您可以使用 @987654322@ 代替 tempfile.mkdtmp() - 这可用于 with 并自动清理目录:

from tempfile import TemporaryDirectory

with TemporaryDirectory() as temp_dir:
    # ... do something with temp_dir
# automatically cleaned up when context exited

如果您使用的是较早版本的 Python(至少 2.5,with 也是如此),您可以使用 backports.tempfile;见Nicholas Bishop’s answertempfile.TemporaryDirectory context manager in Python 2.7

创建自己的课程既简单又富有启发性,称为 context manager. __enter__() 方法的返回值绑定到as 子句的目标,而__exit__() 方法在上下文退出时被调用——即使是异常——并执行清理。

import shutil
import tempfile

class TemporaryDirectory(object):
    """Context manager for tempfile.mkdtemp() so it's usable with "with" statement."""
    def __enter__(self):
        self.name = tempfile.mkdtemp()
        return self.name

    def __exit__(self, exc_type, exc_value, traceback):
        shutil.rmtree(self.name)

您可以使用 @987654327@ 装饰器简化此操作,因此您无需手动编写上下文管理器。 yield之前的代码在进入上下文时执行,yield值绑定到as的目标,yield之后的代码在退出上下文时执行。这基本上是一个封装资源获取和释放的coroutine,其中yield 将控制权交给with 子句的suite(正文)。请注意,这里您确实需要有一个try...finally 块,因为@contextlib.contextmanager 不会在yield 中捕获异常——这只是将资源管理纳入协程。

from contextlib import contextmanager
import tempfile
import shutil

@contextmanager
def TemporaryDirectory():
    name = tempfile.mkdtemp()
    try:
        yield name
    finally:
        shutil.rmtree(name)

正如 simplelizz 所指出的,如果您不介意已经删除的目录(上面的代码假设不会发生这种情况),您可以捕获“没有这样的文件或目录”异常,如下所示:

import errno
# ...
try:
    shutil.rmtree(self.name)
except OSError as e:
    # Reraise unless ENOENT: No such file or directory
    # (ok if directory has already been deleted)
    if e.errno != errno.ENOENT:
        raise

您可以与tempfile.py中的标准实现进行比较;即使是这个简单的类也有错误并且多年来不断发展。

有关with的背景,请参阅:

【讨论】:

【解决方案2】:

阅读documentation,很简单。 ;) 来自文档:该目录只能通过创建用户 ID 进行读取、写入和搜索。

要删除临时目录,请尝试以下操作:

import errno
import shutil
import tempfile

try:
    tmp_dir = tempfile.mkdtemp()  # create dir
    # ... do something
finally:
    try:
        shutil.rmtree(tmp_dir)  # delete directory
    except OSError as exc:
        if exc.errno != errno.ENOENT:  # ENOENT - no such file or directory
            raise  # re-raise exception

您也可以尝试tempdir 包或查看其来源。

【讨论】:

  • 这似乎不起作用。运行时出现“权限被拒绝”错误。此外,我在磁盘上有许多要删除的 tmp 目录。我也不能手动删除它们。删除 mkdtemp 创建的树的正确方法是什么?谢谢。
  • 可能是你系统上 umask 值的问题?您可以在 umask 命令输出中看到它,尝试通过执行:umask 022 将其更改为 022,然后再次尝试我的代码。
  • FWIW,你的回答比文档更好。
  • 这是一个很好的答案。但是请注意,tempdir 文档链接当前已失效。
【解决方案3】:

我在使用 TemporaryDirectory() 时遇到了相同/类似的问题,它基本上涵盖了您在上面定义的功能。

我的问题是由于使用了临时目录。我曾经通过克隆 git 存储库来填充内容,碰巧在此过程中创建了只读文件,并且正常退出这些只读临时文件导致完整的临时目录留在那里。

确实将 TemporaryDirectory 继承到我自己的类,并使用以下代码覆盖了类方法 _cleanup。

super() 之前的代码可能会优化,但对我来说,性能不是问题。

我确实使用了武力并阅读了“tempfile”的来源

import tempfile
import shutil
import stat 

class myTempDir(tempfile.TemporaryDirectory):
    @classmethod
    def _cleanup(self,name, warn_message):
        for root, dirs, files in os.walk(name):
            for fname in files:
                full_path = os.path.join(root, fname)
                os.chmod(full_path ,stat.S_IWRITE)
        super()

解决方案适用于带有 Python 3 的 Windows 10

【讨论】:

    【解决方案4】:

    我认为用户有责任删除使用 tempfile.mkdtemp() 创建的临时目录及其内容。 它不会像临时文件一样自动删除。 删除目录的方法有很多种

    如果目录为空,可以使用

    `os.removedirs or os.rmdir`
    

    注意只有当目录为空时才能使用,否则会引发

    操作系统错误

    这将删除整个目录路径:

    import shutil    
    shutil.rmtree('/path/to/your/dir/')
    

    使用时要小心,它会删除整个目录和其中的文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-06
      • 1970-01-01
      • 2018-10-13
      相关资源
      最近更新 更多