HOWTO · Python
Python 中把一个文本文件读成一个列表
本教程演示了如何将文本文件读取到 python 列表中。
本页内容
要将文本文件读入 Python 列表,先确定每个列表项代表什么:一行物理行、一个分隔字段、一条记录,还是一个数值。对于普通文本,readlines() 会在读取文件时逐行构建结果列表,并在存在行结束符时将其保留。相比之下,read() 后接 splitlines() 会先将完整文件内容保存在一个字符串中,再创建不带行结束符的行字符串列表。如果只需处理大型文件,可以逐行迭代,而不必收集所有行。
下面的示例会各自创建一个小型输入文件,因此你可以将临时路径替换为自己的文件路径来改用这些示例。它们仅用于说明,本次写作阶段并未执行。
使用 readlines() 读取各行
readlines() 返回一个列表,其中的元素是文件各行。如果某行带有行结束符,该字符通常也会包含在字符串中,因此在显示列表时可能会看到 \n。读取完列表后,上下文管理器会关闭文件。
运行此示例:
本节中的代码以及显示的标签或输出仍为英文。
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "notes.txt"
path.write_text("First line\nSecond line\nThird line\n", encoding="utf-8")
with path.open(encoding="utf-8") as file:
lines = file.readlines()
print(lines)
生成的列表会在内存中包含所有行以及它们的行结束符。当文件较小且需要保留每行原始字符串时,这种方法很方便。如果只需处理大型文件,请使用大型文件一节中的循环,而不要存储每一行。
使用列表推导式读取并清理各行
迭代文本文件时,文件会逐行读取。列表推导式可以将这些行整理成列表,而 rstrip("\r\n") 会移除行结束符,但保留文本中原有的空格。
本节中的代码以及显示的标签或输出仍为英文。
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "names.txt"
path.write_text(" Ada \nLin\n", encoding="utf-8")
with path.open(encoding="utf-8") as file:
names = [line.rstrip("\r\n") for line in file]
print(names)
也可以使用 strip(),但它会移除字符串两端的空白字符,包括行中有意义的空格。虽然列表推导式逐步读取输入,最终列表仍会将每个清理后的字符串保存在内存中。只有在确实需要列表且文件大小适合可用内存时,才选择这种方法。
读取整个文件并按行拆分
当需要先获取完整文本再将其拆分为各行时,可以先调用 read(),再调用 splitlines()。splitlines() 能识别常见的行边界,并且返回的字符串不包含这些分隔符。
本节中的代码以及显示的标签或输出仍为英文。
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "poem.txt"
path.write_text("Red\nBlue\nGold\n", encoding="utf-8")
with path.open(encoding="utf-8") as file:
content = file.read()
lines = content.splitlines()
print(lines)
完整字符串和生成的列表都会占用内存,因此这种方法不适合非常大的输入。处理逐行文本时,使用列表推导式或循环可以避免先把整个文件额外构建成一个字符串。
逐行处理大型文件
如果每条记录都能独立处理,可以在文件循环中处理它,并且只保留任务所需的状态。此示例统计非空行数,不会将文件内容保留为列表。
本节中的代码以及显示的标签或输出仍为英文。
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "events.txt"
path.write_text("login\nview\nlogout\n", encoding="utf-8")
count = 0
with path.open(encoding="utf-8") as file:
for line in file:
if line.strip():
count += 1
print(count)
这种方式只需为当前行和小型计数器保留有限的内存。如果任务确实需要列表,可以在循环中追加处理后的字符串,但要注意列表会随文件增大;仅使用循环并不能让收集到列表中的数据节省内存。打开不存在的路径会引发 FileNotFoundError;请使用正确的路径,或在应用程序能够恢复的地方处理该错误。
使用 split() 拆分由分隔符分开的文本
对于只使用一个已知分隔符的简单格式,可以读取文本,再调用 split() 并传入该分隔符。结果是由字符串组成的列表,而不是数值;分隔符会被移除。这适用于冒号分隔值等格式固定的文本,但无法处理 CSV 引号规则,也无法正确解析引号字段中包含的分隔符。
本节中的代码以及显示的标签或输出仍为英文。
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "colors.txt"
path.write_text("red|green|blue", encoding="utf-8")
with path.open(encoding="utf-8") as file:
colors = file.read().split("|")
print(colors)
除非明确清理每个字段,否则空白字符会保留。例如,如果字段两侧的空格只是格式而不是数据,可以使用包含 field.strip() 的列表推导式来移除它们。
使用 csv.reader() 读取分隔数据的各行
对于 CSV 或类似的分隔数据,可以使用 Python 的 csv 模块,让它按照格式规则解析引号内的分隔符和转义引号。csv.reader() 会为每行生成一个由字符串组成的列表。只有在需要将所有行都保存在内存中时,才将迭代器转换为列表;大型文件也可以直接迭代处理。
本节中的代码以及显示的标签或输出仍为英文。
import csv
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "people.csv"
path.write_text('name,city\n"Doe, Jane",Paris\nAlex,Rome\n', encoding="utf-8")
with path.open(newline="", encoding="utf-8") as file:
rows = list(csv.reader(file))
print(rows)
每一行都会单独保留;如果输入中有表头,表头也会作为一行保留。如果调用方只需要数据记录,应明确跳过或处理表头;仅索引第一行并不能读取多行文件。按照 CSV 模块的建议,打开 CSV 文本文件时使用 newline=""。
使用 NumPy 加载数值数据
对于行列结构规整的数值文本数据,NumPy 的 loadtxt() 可以将数值解析为数组。NumPy 是一项额外依赖。它返回的是数组,而不是 Python 列表;如果需要普通的嵌套列表,可以调用 tolist()。此示例假设文件中的数值使用一致的分隔方式,且没有表头。
本节中的代码以及显示的标签或输出仍为英文。
from pathlib import Path
from tempfile import TemporaryDirectory
try:
import numpy as np
except ImportError:
print("Install NumPy to run this example.")
else:
with TemporaryDirectory() as directory:
path = Path(directory) / "measurements.csv"
path.write_text("1.5,2.0\n3.5,4.0\n", encoding="utf-8")
values = np.loadtxt(path, delimiter=",")
print(values.tolist())
如果各行长度可能不同、数据中包含文本,或需要遵循 CSV 引号规则,请改用 csv.reader()。当数据为数值且需要进行数组运算时,可以选择 NumPy;它的解析方式和数组表示形式都不同于由行字符串组成的列表。