如果你用content = open('Path/to/file', 'r')读取整个文件。read()是文件句柄一直打开直到脚本退出?是否有更简洁的方法来读取整个文件?


当前回答

不再以单个字符串的形式检索文件内容, 它可以方便地将内容存储为文件包含的所有行列表:

with open('Path/to/file', 'r') as content_file:
    content_list = content_file.read().strip().split("\n")

可以看到,我们需要将.strip().split("\n")添加到这个线程的主答案中。

这里,.strip()只是删除整个文件字符串结尾的空格和换行符, 而.split("\n")通过在每个换行符\n处拆分整个文件字符串来生成实际的列表。

此外, 通过这种方式,整个文件内容可以存储在一个变量中,这在某些情况下可能是需要的,而不是像前面的回答中指出的那样逐行遍历文件。

其他回答

如果您必须一行一行地读取文件来处理每一行,您可以使用

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

这个问题的答案在某种程度上取决于特定的Python实现。

要理解这是关于什么的,请特别注意实际的file对象。在代码中,该对象仅在表达式中被提及一次,并且在read()调用返回后立即不可访问。

这意味着文件对象是垃圾。剩下的唯一问题是“垃圾收集器什么时候收集文件对象?”

在使用引用计数器的CPython中,这种垃圾会立即被注意到,因此它会立即被收集。其他python实现通常不是这样。

一个更好的解决方案,确保文件是关闭的,是这样的模式:

with open('Path/to/file', 'r') as content_file:
    content = content_file.read()

它总是在块结束后立即关闭文件;即使出现异常。

编辑:说得更清楚点:

除了file.__exit__()在带有上下文管理器的设置中被“自动”调用之外,自动调用file.close()的唯一其他方式(即,除了显式地自己调用它之外)是通过file.__del__()。这就引出了一个问题:__del__()什么时候被调用?

一个正确编写的程序不能假定终结器将在程序终止之前的任何时候运行。

——https://devblogs.microsoft.com/oldnewthing/20100809-00/?p=13203

特别是:

Objects are never explicitly destroyed; however, when they become unreachable they may be garbage-collected. An implementation is allowed to postpone garbage collection or omit it altogether — it is a matter of implementation quality how garbage collection is implemented, as long as no objects are collected that are still reachable. [...] CPython currently uses a reference-counting scheme with (optional) delayed detection of cyclically linked garbage, which collects most objects as soon as they become unreachable, but is not guaranteed to collect garbage containing circular references.

——https://docs.python.org/3.5/reference/datamodel.html objects-values-and-types

(强调我的)

但正如它所表明的,其他实现可能有其他行为。例如,PyPy有6个不同的垃圾收集实现!

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

不再以单个字符串的形式检索文件内容, 它可以方便地将内容存储为文件包含的所有行列表:

with open('Path/to/file', 'r') as content_file:
    content_list = content_file.read().strip().split("\n")

可以看到,我们需要将.strip().split("\n")添加到这个线程的主答案中。

这里,.strip()只是删除整个文件字符串结尾的空格和换行符, 而.split("\n")通过在每个换行符\n处拆分整个文件字符串来生成实际的列表。

此外, 通过这种方式,整个文件内容可以存储在一个变量中,这在某些情况下可能是需要的,而不是像前面的回答中指出的那样逐行遍历文件。