如何用Python每次读取文件的两行?

91 投票
14 回答
91031 浏览
提问于 2025-04-15 15:34

我正在编写一个Python脚本,用来解析一个文本文件。这个文本文件的格式是每个元素占用两行。为了方便起见,我想在解析之前先读取这两行。请问在Python中可以这样做吗?

我想做的事情类似于:

f = open(filename, "r")
for line in f:
    line1 = line
    line2 = f.readline()

f.close

但是这样做会出错,提示信息是:

ValueError: 混合使用迭代和读取方法会导致数据丢失

相关内容:

14 个回答

31

使用 next() 函数,比如:

with open("file") as f:
    for line in f:
        print(line)
        nextline = next(f)
        print("next line", nextline)
        ....
58
import itertools
with open('a') as f:
    for line1,line2 in itertools.zip_longest(*[f]*2):
        print(line1,line2)

itertools.zip_longest() 是一个返回迭代器的函数,所以即使文件有数十亿行,它也能很好地工作。

如果行数是奇数,那么在最后一次迭代时,line2 会被设置为 None

在 Python2 中,你需要用 izip_longest 来代替。


在评论中,有人问这个方法是否会先读取整个文件,然后再第二次遍历文件。我认为不会。with open('a') as f 这一行是打开了一个文件句柄,但并没有读取文件。f 是一个迭代器,所以它的内容不会被读取,直到你请求它。zip_longest 接受迭代器作为参数,并返回一个迭代器。

确实,zip_longest 是对同一个迭代器 f 调用了两次。但实际上发生的事情是,第一次对第一个参数调用 next(f),然后对第二个参数也调用 next()。因为 next() 是在同一个底层迭代器上调用的,所以会依次返回后续的行。这和一次性读取整个文件是非常不同的。实际上,使用迭代器的目的就是为了避免一次性读取整个文件。

因此,我相信这个方法按预期工作——文件只被 for 循环读取了一次。

为了验证这一点,我对比了使用 zip_longest 的方法和使用 f.readlines() 的方法。我在最后加了一个 input() 来暂停脚本,并分别运行了 ps axuw

% ps axuw | grep zip_longest_method.py

unutbu 11119 2.2 0.2 4520 2712 pts/0 S+ 21:14 0:00 python /home/unutbu/pybin/zip_longest_method.py bigfile

% ps axuw | grep readlines_method.py

unutbu 11317 6.5 8.8 93908 91680 pts/0 S+ 21:16 0:00 python /home/unutbu/pybin/readlines_method.py bigfile

从结果来看,readlines 显然是一次性读取了整个文件。由于 zip_longest_method 使用的内存明显更少,我认为可以安全地得出结论,它并没有一次性读取整个文件。

58

类似的问题可以在 这里找到。你不能把循环和逐行读取混在一起,所以你需要选择使用其中一种方式。

while True:
    line1 = f.readline()
    line2 = f.readline()
    if not line2: break  # EOF
    ...

撰写回答