重命名 Python 中的临时文件

Renaming temporary files in Python

我想执行以下操作。创建一个临时文件并处理它。如果成功,将其重命名为真实文件。如果失败,则删除该文件。

我尝试了以下方法:

with tempfile.NamedTemporaryFile(dir=os.getcwd()) as f:
    f.write(b'foobar')
    f.delete = False
    f.flush()
    os.rename(f.name, 'foobar')

但是,当我试图删除它时,我仍然得到一个异常,该文件不存在。我可能会使用 try-catch 来忽略此错误,但这会很丑陋并且也可能会忽略其他错误。或者我可以使用 mkstemp() 并自己管理删除,但这有一个问题,它 returns 是一个文件描述符而不是文件对象,而且我找不到从文件描述符。

这个问题有什么好的解决方法吗?

这可以通过 NamedTemporaryFile class 来实现。关闭后,您可以将其移动到所需的 location/filename。为避免删除错误,您需要在移动前关闭文件。

from tempfile import NamedTemporaryFile
import shutil

with NamedTemporaryFile(delete=False) as tmp:
    tmp.write(b'hi')

# move file to target location/name
shutil.move(tmp.name, 'target')

初始化的时候需要传delete=False,后面设置f.delete = False是不行的。在用这段代码编写后,我能够重命名它:

with tempfile.NamedTemporaryFile(dir=os.getcwd(), delete=False) as f:
    f.write(b'foobar')
    f.flush()
    os.rename(f.name, 'foobar')

我查看了 Lib/tempfile.py 的代码以确认此行为。

当您调用 NamedTemporartyFile 时,它会初始化 returns 在同一文件中定义的 _TemporaryFileWrapper class 的一个实例。看看这个class的__init__()

def __init__(self, file, name, delete=True):
        self.file = file
        self.name = name
        self.delete = delete
        self._closer = _TemporaryFileCloser(file, name, delete)

这里是 _TemporaryFileCloser__init__() class:

def __init__(self, file, name, delete=True):
        self.file = file
        self.name = name
        self.delete = delete

当您退出 with 语句时,在关闭文件期间,将检查 _TemporaryFileCloserself.delete 属性。当您执行 f.delete = False 时,您更改了 _TemporaryFileWrapper class 的 self.delete 属性,而不是 _TemporaryFileCloser class。因此,关闭行为不会改变,即使在开发人员方面看起来是这样。因此,您必须在 with 语句的初始化期间传递 delete=False,就像我的代码示例中那样。

如果你还想修改行为,你可以访问self._closer属性,但是它会有点难看。

with tempfile.NamedTemporaryFile(dir=os.getcwd()) as f:
    f.write(b'foobar')
    f.flush()
    f._closer.delete = False
    os.rename(f.name, 'foobar')

顺便说一句,我在 Windows 10 上对 Ubuntu WSL 执行了此操作。我不确定您使用的是哪个 OS,这可能会影响行为。