读取整个文件会保持文件句柄打开吗?

401 投票
4 回答
496259 浏览
提问于 2025-04-17 02:15

如果你用 content = open('Path/to/file', 'r').read() 这个方法读取了一个文件,那么在脚本结束之前,这个文件的句柄会一直保持打开状态吗?有没有更简洁的方法来读取整个文件呢?

4 个回答

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
119

你可以使用 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()
624

这个问题的答案有点依赖于具体的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种不同的垃圾收集实现

撰写回答