避免删除 SpooledTemporaryFile

Avoiding deletion of SpooledTemporaryFile

Python 中临时文件模块的 SpooledTemporaryFile 是在系统内存中创建的临时文件,而不是在光盘上。但是,可以随时通过调用适当命名的 rollover 方法将其滚动到光盘。一旦文件关闭,它就会被删除,而这正是我要防止的。

NamedTemporaryFile 在其构造函数中有一个 delete 关键字参数来完成这项工作,但它不适用于 SpooledTemporaryFile。解决此问题的一种方法是在关闭此文件之前复制该文件。这需要额外的 copy 操作,并且必须采取预防措施以避免竞争条件。它还需要更多资源。有什么解决方法吗?

尽管io.StringIO is available at my disposal, I decided to take a look at the source code - tempfile.py。这是该模块中事件链的进展方式:

  • A SpooledTemporaryFile 作为 io.StringIOio.BytesIO 对象启动。
  • 回滚到光盘时,创建一个TemporaryFile文件对象,IO流对象被丢弃进行垃圾回收。
  • 这个新文件对于几个平台是不同的。在 Windows 或 CygWin 系统上,这个新文件是 NamedTemporaryFile,它的关闭方法通过名为 _TemporaryFileCloser 的包装器 class 访问。我们可以覆盖一些方法并跳过一些箍 * 最终设置 delete=False 以实现我们的目标。
  • 在 posix 系统上,新文件只是另一个易失性 IO 流 (叹息...)

* 解决方法是将其子class 并覆盖rollover 方法。下面的代码适用于 posix 和 Windows 系统。在 Windows 上,您可以跳过 rollover 部分 - 只需要 __init__

from tempfile import SpooledTemporaryFile

class CustomSpooled(SpooledTemporaryFile):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # This dict will be passed on to the NamedTempFile constructor one we
        # roll over our file. We are adding the delete=False argument.
        self._TemporaryFileArgs = {'mode': mode, 'buffering': buffering,
                                   'suffix': suffix, 'prefix': prefix,
                                   'encoding': encoding, 'newline': newline,
                                   'dir': dir, 'delete': False}

    def rollover(self):
        # This is overidden to get that NamedTemperoraryFile
        # Everythng else is just the same
        if self._rolled: return
        file = self._file
        newfile = self._file = NamedTemporaryFile(**self._TemporaryFileArgs)
        del self._TemporaryFileArgs

        newfile.write(file.getvalue())
        newfile.seek(file.tell(), 0)

        self._rolled = True

CAUTION! This is evidently a dirty hack, therefore I do not recommend this for production code or anything of the sort.