上下文管理器删除tempfile

时间:2016-06-24 03:47:18

标签: python

我尝试编写上下文管理器,以便在处理后有条件地清理tempfile。简化为:

import os
from contextlib import contextmanager
from subprocess import Popen
from tempfile import NamedTemporaryFile


@contextmanager
def temp(cleanup=True):
    tmp = NamedTemporaryFile(delete=False)
    try:
        yield tmp
    finally:
        cleanup and os.remove(tmp.name)

with temp() as tmp:
    tmp.write(b'Hi')
    p = Popen(['cmd', '/c', 'type', tmp.name])
    p.wait()

尝试此脚本会引发:

Traceback (most recent call last):
  File "C:\temp\test.py", line 18, in <module>
    p.wait()
  File "C:\Python35\lib\contextlib.py", line 66, in __exit__
    next(self.gen)
  File "C:\temp\test.py", line 13, in temp
    cleanup and os.remove(tmp.name)
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Temp\\tmp79su99sg'

我希望在语句循环结束时释放tempfile,而显然不是。

2 个答案:

答案 0 :(得分:3)

当您尝试删除文件时,您的文件确实已打开。 在删除文件之前,您必须先关闭该文件:

@contextmanager
def temp(cleanup=True):
    tmp = NamedTemporaryFile(delete=False)
    try:
        yield tmp
    finally:
        tmp.close() #closes the file, so we can right remove it
        cleanup and os.remove(tmp.name)

另一个选择是使用context-manager包装文件对象:

@contextmanager
def temp(cleanup=True):
    tmp = NamedTemporaryFile(delete=False)
    try:
        with tmp:
            yield tmp
    finally:
        cleanup and os.remove(tmp.name)

答案 1 :(得分:3)

您可以将NamedTemporaryFile用作上下文管理器:

from tempfile import NamedTemporaryFile

with NamedTemporaryFile() as tmp:
    tmp.write(b'Hi')
    p = Popen(['cmd', '/c', 'type', tmp.name])
    p.wait()
# Here the file is closed and thus deleted