如何删除使用tempfile.mkdtemp创建的目录?
我有一个Python程序,它通过使用tempfile.mkdtemp
在/temp
下创建临时目录。不幸的是,这个Python程序在使用完这些目录后没有删除它们。所以现在磁盘空间不够用了。
问题:
- 我该如何手动删除
/temp
下留下的临时目录?我尝试手动删除,但出现了“权限被拒绝”的错误。 - 在Python程序中,如何在使用完
temp
目录后将其删除?
5 个回答
我遇到过类似的问题,使用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()
这个解决方案在Windows 10和Python 3上有效。
看看这个文档,很简单哦。;) 文档里说,这个临时目录只有创建它的用户可以读取、写入和搜索。
如果你想删除这个临时目录,可以试试下面的代码:
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这个包,或者看看它的源代码。
在Python中管理资源(比如文件)时,最好的做法是使用with
这个关键词,它可以自动释放资源(也就是清理,比如关闭文件);这个功能从Python 2.5开始就有了。
从Python 3.2开始,你可以使用tempfile.TemporaryDirectory()
来代替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的回答,了解Python 2.7中的tempfile.TemporaryDirectory上下文管理器。
你可以轻松地自己写一个类,叫做上下文管理器。__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)
你可以使用@contextlib.contextmanager
这个装饰器来简化这个过程,这样你就不需要手动编写上下文管理器。yield
之前的代码在进入上下文时执行,yield的值会绑定到as
后面的目标,而yield
之后的代码在退出上下文时执行。这本质上是一个协程,它封装了资源的获取和释放,yield
将控制权交给with
语句的主体。需要注意的是,这里你确实需要有一个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)
正如simplylizz所提到的,如果你不介意目录已经被删除(上面的代码假设不会发生这种情况),你可以像下面这样捕获“No such file or directory”的异常:
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
中找到;即使是这个简单的类,多年来也出现过bug并不断演变。
关于with
的背景,可以参考:
- Python教程:文件对象的方法
- with语句上下文管理器
- PEP 343 -- "with"语句