用 Python 读取文件

介绍

为了处理存储的数据,文件处理成为每个专业 Python 程序员的核心知识。 从最早的版本开始,读取和写入数据到文件都是 Python 的内置功能。 与 C 或 Java 等其他编程语言相比,它非常简单,只需要几行代码。 此外,无需加载额外的模块即可正确执行此操作。

在本文中,我们将通过示例解释如何使用 Python 读取文件。 一些示例包括逐行读取文件,作为一个块(一次定义的行数),以及一次读取文件。 此外,我们将向您展示一种仅从文件中读取特定行的方法,而无需搜索整个文件。

Python中的文件基础

操作文件的常用方法是 open() 打开文件, seek() 将文件的当前位置设置为给定的偏移量,以及 close() 完成使用后关闭文件对象。 内置的 open() 函数返回一个文件句柄,该句柄代表一个文件对象,用于访问文件以进行读取、写入或追加。

当打开一个文件进行读取时,Python 需要准确地知道系统应该如何打开该文件。 有两种访问模式可用——读取和以二进制模式读取。 使用的各自标志是 'r''rb', 并且必须在使用内置打开文件时指定 open() 功能。 第一种模式包括解释特殊字符,如“CR”(回车)和“LF”(换行)来表示换行符,而二进制模式允许您以原始模式读取数据——数据按原样存储无需进一步解释。

打开文件后, open() 函数将返回一个文件对象给你。 这些文件对象具有类似的方法 read(), readline(), write(), tell()seek(). 虽然某些文件对象(或类似文件的对象)的方法比此处列出的方法多,但这些是最常见的。 并非所有文件对象都需要实现所有文件方法。

逐行读取文件

第一个例子的灵感来自于两种编程语言——C 和 C++。 这可能是最直观的方法 - 使用 open() 功能, 逐行读取文件 使用 readline() 方法,并在读取后立即输出该行。

这里使用的是一个 while 循环持续从文件中读取,只要 readline() 方法不断返回数据。 如果到达文件结尾 (EOF) while 循环停止并关闭文件对象,释放资源供其他程序使用:


filename = "test.txt"

filehandle = open(filename, 'r')
while True:
    
    line = filehandle.readline()
    if not line:
        break
    print(line)


filehandle.close()

您可能已经注意到,我们在此示例中明确打开和关闭了文件。 虽然 Python 解释器会在 Python 程序执行结束时自动关闭打开的文件,但通过显式关闭文件 close() 是一种很好的编程风格,不应该被遗忘。

作为一项改进, 方便的迭代器协议 在 Python 2.3 中引入。 这使您可以简化 readline 循环:


filename = "test.txt"
for line in open(filename, 'r'):
    print(line)

这里使用的是一个 for 循环结合 in 迭代器。 当前行在 in 迭代器,从文件中读取,其内容输出到 stdout. 当文件超出范围时,Python 会为您提供文件的打开和关闭。 虽然效率低下,但这使您不必再处理文件句柄。

不幸的是,上面的代码不太明确,并且依赖于 Python 的内部垃圾收集来处理关闭文件。

在 Python 2.5 中引入, with command 进一步封装了整个过程,并且在整个作用域代码块中只处理一次打开和关闭文件:


filename = "test.txt"
with open(filename, 'r') as filehandle:
    for line in filehandle:
        print(line)

的结合 with 声明和 open() 命令只打开文件一次。 如果成功的话 for 执行循环,并打印该行的内容 stdout.

此外,使用 with 声明有副作用。 在内部,Python 解释器创建一个 tryfinally-block 封装从文件中读取的内容。 下面的例子展示了在 Python 内部本质上发生的事情 with 代码块:

try:
    filehandle = open(filename, 'r')
    
finally:
    filehandle.close()

以行块的形式读取文件

到目前为止,我们已经逐行处理了一个文件。 这对于大文件来说相当慢,可以通过同时读取多行来改进。 为实现这一目标, islice() 的方法 迭代工具 模块开始发挥作用。 此外,它用作迭代器并返回一大块数据,其中包括 n 线。 在文件末尾,结果可能会更短,最后,调用将返回一个空列表:

from itertools import islice

filename = "test.txt"

number_of_lines = 5

with open(filename, 'r') as input_file:
    lines_cache = islice(input_file, number_of_lines)
   
    for current_line in lines_cache:
        print (current_line)

从文件中读取特定行

使用上面显示的方法,我们还可以执行其他有用的操作,例如从文件中读取特定行。 为此,我们使用计数器并在遍历文件时打印相应的行:


filename = "test.txt"

line_number = 3
print (f"line {line_number} of {filename} is: ")

with open(filename, 'r') as filehandle:
current_line = 1
    for line in filehandle:
        if current_line == line_number:
            print(line)
            break
        current_line += 1

这应该很容易理解,但是比前面的例子要长一点。 它可以使用缩短 线缓存 模块。

下面的例子展示了如何使用 getline() 方法。 如果请求的行号超出文件中有效行的范围,则 getline() 方法返回一个空字符串:


import linecache

filename = "test.txt"

line_number = 3

line = linecache.getline(filename, line_number)
print (f"line {line_number} of {filename}:")
print (line)

一次读取整个文件

最后但并非最不重要的一点是,我们将看一个与前一个示例非常不同的案例——一次读取整个文件。

请记住,在大多数情况下,您应该有足够的内存来读取整个文件,因为字符不会占用太多空间,但要对大文件感到厌烦。 以下示例使用了 with 声明,以及 read() 方法。 在这种情况下,我们将使用 read() 将文件内容作为数据流加载:

查看我们的 Git 学习实践指南,其中包含最佳实践、行业认可的标准以及随附的备忘单。 停止谷歌搜索 Git 命令,实际上 学习 它!


filename = "test.txt"

with open(filename, 'r') as filehandle:
    filecontent = filehandle.read()
    print (filecontent)

Python 还提供 readlines() 方法,类似于 readline() 第一个例子的方法。 相比之下 read(),文件内容存储在一个列表中,其中每一行内容是一个项目:


filename = "test.txt"

with open(filename, 'r') as filehandle:
    filecontent = filehandle.readlines()
    for line in filecontent:
        print (line)

readlines() 将从文件中读取内容,直到到达 EOF,请记住,您还可以通过提供 sizehint 参数,这是要读取的字节数。

结论

像往常一样,读取文件内容的方法不止一种。 在速度方面,它们都或多或少属于同一类别。 哪种解决方案最适合您取决于您​​的具体用例。 我们认为看看什么是可能的,然后选择最适合的解决方案是非常有帮助的。

虽然 Python 大大简化了读取文件的过程,但有时它仍然会变得很棘手,在这种情况下,我建议你看看 官方 Python 文档 获取更多信息。

时间戳记:

更多来自 堆栈滥用