6

的描述tempfile.NamedTemporaryFile()说:

如果delete为 true(默认值),则文件一关闭就会被删除。

在某些情况下,这意味着在 Python 解释器结束后文件不会被删除。例如,在 下运行以下测试时 py.test,临时文件仍然存在:

from __future__ import division, print_function, absolute_import
import tempfile
import unittest2 as unittest
class cache_tests(unittest.TestCase):
    def setUp(self):
        self.dbfile = tempfile.NamedTemporaryFile()
    def test_get(self):
        self.assertEqual('foo', 'foo')

在某种程度上这是有道理的,因为这个程序从不明确地关闭文件对象。关闭对象的唯一另一种方法可能是在__del__析构函数中,但这里的语言参考声明“不能保证__del__()在解释器退出时为仍然存在的对象调用方法。 ”所以一切都与到目前为止的文档。

但是,我对此的含义感到困惑。如果不能保证在解释器退出时关闭文件对象,那么即使程序正常退出,成功写入(缓冲的)文件对象的一些数据是否会丢失,因为它仍然在文件对象的缓冲区中,并且文件对象从未关闭?

不知何故,这对我来说似乎不太可能和非 Pythonic,并且 open() 文档也不包含任何此类警告。所以我(暂时)得出结论,文件对象毕竟保证是关闭的。

但是这个魔法是怎么发生的,为什么不能NamedTemporaryFile()使用同样的魔法来确保文件被删除呢?

编辑:请注意,我在这里不是在谈论文件描述符(由操作系统缓冲并在程序退出时由操作系统关闭),而是关于可能实现自己的缓冲的 Python 文件对象。

4

3 回答 3

14

在 Windows 上,NamedTemporaryFile 使用特定于 Windows 的扩展名 (os.O_TEMPORARY) 来确保文件在关闭时被删除。如果进程以任何方式被终止,这也可能有效。但是在 POSIX 上没有明显的等价物,很可能是因为在 POSIX 上您可以简单地删除仍在使用的文件;它只删除名称,并且文件的内容仅在关闭后才被删除(以任何方式)。但确实假设我们希望文件名在文件关闭之前一直存在,就像 NamedTemporaryFile 一样,那么我们需要“魔法”。

我们不能使用与刷新缓冲文件相同的魔法。发生的情况是 C 库处理它(在 Python 2 中):文件是 C 中的 FILE 对象,并且 C 保证它们在正常程序退出时被刷新(但如果进程被终止则不会)。在 Python 3 的情况下,有自定义 C 代码可以实现相同的效果。但它特定于这个用例,而不是任何可直接重用的东西。

这就是 NamedTemporaryFile 使用自定义__del__. 事实上,__del__不能保证在解释器退出时被调用。(我们可以通过一个引用 NamedTemporaryFile 实例的全局引用循环来证明这一点;或者运行 PyPy 而不是 CPython。)

作为旁注,NamedTemporaryFile 可以更稳健地实现,例如通过注册自身atexit以确保随后删除文件名。但是您也可以自己调用它:如果您的进程不使用无限数量的 NamedTemporaryFiles,那么它就是atexit.register(my_named_temporary_file.close).

于 2013-04-12T10:05:23.943 回答
1

在任何版本的 *nix 上,所有文件描述符都会在进程完成时关闭,这由操作系统负责。Windows 在这方面可能完全相同。如果不深入研究源代码,我不能以 100% 的权威说实际发生了什么,但可能发生的事情是:

  • If deleteis False, unlink()(或其他操作系统上类似的函数)被调用。这意味着当进程退出并且没有更多打开的文件描述符时,该文件将被自动删除。在进程运行时,该文件仍将保留。

  • 如果deleteTrue,则可能使用了 C 函数remove()。这将在进程退出之前强制删除文件。

于 2013-04-10T05:27:34.377 回答
-1

文件缓冲由操作系统处理。如果您打开文件后不关闭它,那是因为您假设操作系统将在所有者存在后刷新缓冲区并关闭文件。这不是 Python 魔术,这是你的操作系统在做的事情。该__del__()方法与 Python 相关,需要显式调用。

于 2013-04-10T05:26:28.543 回答