读取整个文件会保持文件句柄打开吗?
如果你用 content = open('Path/to/file', 'r').read()
这个方法读取了一个文件,那么在脚本结束之前,这个文件的句柄会一直保持打开状态吗?有没有更简洁的方法来读取整个文件呢?
4 个回答
好吧,如果你需要逐行读取文件来处理每一行内容,你可以使用
with open('Path/to/file', 'r') as f:
s = f.readline()
while s:
# do whatever you want to
s = f.readline()
或者还有更好的方法:
with open('Path/to/file') as f:
for line in f:
# do whatever you want to
你可以使用 pathlib 这个库。
如果你使用的是 Python 3.5 及以上版本:
from pathlib import Path
contents = Path(file_path).read_text()
如果你用的是旧版本的 Python,可以使用 pathlib2:
$ pip install pathlib2
然后:
from pathlib2 import Path
contents = Path(file_path).read_text()
这里是实际的 read_text
实现代码:
def read_text(self, encoding=None, errors=None):
"""
Open the file in text mode, read it, and close the file.
"""
with self.open(mode='r', encoding=encoding, errors=errors) as f:
return f.read()
这个问题的答案有点依赖于具体的Python实现。
要理解这件事,特别要关注实际的file
对象。在你的代码中,这个对象只提到了一次,并且在read()
调用返回后就变得不可访问了。
这意味着这个文件对象就成了垃圾。剩下的问题就是“垃圾收集器什么时候会清理这个文件对象?”
在CPython中,它使用的是引用计数的方法,这种垃圾会立即被发现,因此会立即被清理。但其他的Python实现不一定都是这样。
一个更好的解决方案,确保文件被关闭,可以使用下面的模式:
with open('Path/to/file', 'r') as content_file:
content = content_file.read()
这个模式会在代码块结束后立即关闭文件;即使发生了异常也会如此。
补充说明:更详细地说:
除了在with
上下文管理器中“自动”调用的file.__exit__()
,唯一其他会自动调用file.close()
的方式(也就是不需要你自己显式调用)是通过file.__del__()
。这就引出了一个问题:__del__()
什么时候会被调用呢?
一个写得正确的程序不能假设在程序结束之前,清理函数会在任何时候运行。
-- https://devblogs.microsoft.com/oldnewthing/20100809-00/?p=13203
特别是:
对象从来不会被显式销毁;然而,当它们变得不可达时,可能会被垃圾收集。一个实现可以推迟垃圾收集或完全省略它——垃圾收集的实现质量取决于具体的实现,只要没有收集到仍然可达的对象。
[...]
CPython目前使用的是一种引用计数的方案,并且(可选地)延迟检测循环引用的垃圾,这样大多数对象在变得不可达时会被立即收集,但对于包含循环引用的垃圾并不能保证会被收集。
-- https://docs.python.org/3.5/reference/datamodel.html#objects-values-and-types
(强调是我的)
但正如它所暗示的,其他实现可能会有不同的行为。举个例子,PyPy 有6种不同的垃圾收集实现!