Python关闭文件描述符问题

26
我认为这个问题更多是关于“编码风格”而不是技术问题。
假设我有一行代码:
buf = open('test.txt','r').readlines()
...

文件描述符会自动关闭吗?还是会一直留在内存中? 如果文件描述符没有关闭,关闭它的首选方式是什么?

5个回答

45
如果你将文件对象分配给一个变量,你可以使用.close()显式地关闭它。
f = open('test.txt','r')
buf = f.readlines()
f.close()

或者(更普遍的做法),您可以使用with关键字(Python 2.5及以上版本)如Python文档中所述:

在处理文件对象时,最好使用with关键字。这样做的好处是当套件完成后,文件将被正确关闭,即使在过程中出现异常。与编写等效的try-finally块相比,这也要简短得多:

>>> with open('test.txt','r') as f:
...     buf = f.readlines()
>>> f.closed
True

1
在这种情况下,“buf”将是一个列表 - 它没有“close”方法。 - jsbueno
3
with在Python2.5中已经可用,但需要使用from __future__ import with_statement导入。然而,在Python2.6及以上版本中不再需要这样做。 - Jay Conrod
@jsbueno 谢谢你发现我的错误!我已经更新了答案以反映你的观察!@Jay Conrod,感谢您提供的信息!(我从2.4跳到2.7,所以我从未经历过那个问题!) - sahhhm

17
通常在CPython中,当引用计数降为零时,文件会立即关闭(尽管此行为不能保证在未来版本的CPython中保持不变)。
在其他实现中,例如Jython中,文件将不会被关闭,直到进行垃圾回收,这可能需要很长时间。
代码应该避免因不同实现的行为而运行不同。
如果仅用于快速脚本或尝试在解释器 shell 中使用,那么通常足够好,但对于任何生产工作,您通常应该像Falmarri的答案中那样使用上下文管理器。

1
这种情况在不同的Python实现中会影响程序员,例如当在PyPy上运行Mercurial时,它会耗尽操作系统允许打开的文件数量。Mercurial正在进行更改以解决此问题。 - TryPyPy

6

文件将一直保存在内存中,直到垃圾回收器关闭它。您应该始终明确地关闭文件描述符。只需执行以下操作:

with open('test.txt', 'r') as f:
    buf = f.readlines()

@Hugh Bothwell:嗯,我想这取决于你对“明确”一词的定义。我会称其为明确关闭它。 - Falmarri
1
到目前为止,它更加明确,因为我们现在知道文件将在什么时候关闭,但从编程角度来看,这并不是我所说的明确。 - John La Rooy
2
我会称之为自动关闭文件句柄。 - Jasen

2

它将会自动关闭,但具体取决于实现的时间。最好明确使用一个with块,但如果你只是为自己编写偶尔运行的小脚本,这并不重要。


脚本的大小和运行频率是极其不相关的。如果脚本迭代打开许多文件,如果没有关闭它们,这确实很重要。迟早会用尽句柄并崩溃。 - John Machin
1
你说得对,我漏掉了重要的一部分:这是为他自己和偶尔使用的。因为当他用完文件句柄时,他会注意到。但如果他把这个放在客户现场。 :-/ - Lennart Regebro

1
您也可以尝试使用 os.close(fd) 方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接