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()
不能使用
同样的魔术确保文件被删除?
编辑:请注意,我不是在讨论文件 descriptors (由操作系统缓冲并在程序退出时由操作系统关闭),但关于Python文件可以实现自己缓冲的对象。
答案 0 :(得分: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)
。
答案 1 :(得分:1)
在* nix的任何版本上,当进程完成时,所有文件描述符都将关闭,这由操作系统负责。 Windows在这方面可能完全相同。如果不深入挖掘源代码,我不能100%权威地说实际发生了什么,但可能会发生的是:
如果delete
为False
,则会调用unlink()
(或其他操作系统上与此类似的函数)。这意味着当进程退出并且没有更多打开的文件描述符时,文件将自动删除。当进程正在运行时,该文件仍将保留。
如果delete
为True
,则可能使用C函数remove()
。这将在进程退出之前强行删除文件。
答案 2 :(得分:-1)
文件缓冲由操作系统处理。如果在打开文件后没有关闭文件,那是因为您假设操作系统将刷新缓冲区并在所有者存在后关闭文件。这不是Python魔术,这是你的操作系统做的事情。 __del__()
方法与Python有关,需要显式调用。