Python 现代开发学习笔记

(四)逐行读取与按块处理

1. 文件也是可迭代对象

# 每轮只取得一行;行尾换行仍保留,空白行也不是文件结束。
from pathlib import Path

path = Path("lines.txt")
path.write_text("Python\n\nNumPy\n", encoding="utf-8")
with path.open(encoding="utf-8") as stream:
    for number, line in enumerate(stream, start=1):
        print(number, repr(line))
    print("末尾", repr(stream.readline()))

输出 1 'Python\n'、2 '\n'、3 'NumPy\n'、末尾 ''。空白行有一个换行字符,文件末尾才没有新字符。strip() 还会去掉两端其他空白;若只准备移除行尾,可以写 rstrip("\r\n")。

read() 把全部剩余内容收进一个对象,readlines() 收进一个行列表;for line in stream 则逐行取得。在上一章的生成器中处理这些行时,后续统计可以一行接一行推进。

2. 二进制按块读取

# 一次取最多四个字节,不必先把完整文件读进内存。
from pathlib import Path

path = Path("chunks.bin")
path.write_bytes(b"abcdefghi")
total = 0
with path.open("rb") as stream:
    while True:
        chunk = stream.read(4)
        if not chunk:
            break
        total += len(chunk)
        print(chunk)
print("总字节数", total)

输出 b'abcd'、b'efgh'、b'i'、总字节数 9。总文件大小为 n、块大小为 b 时,读取总量仍是 O(n)O(n),这段处理额外保留约 O(b)O(b) 字节。逐行读取的空间还随最长一行增长,不能只用文件总行数判断每次读取占多少空间。

3. 用 batched 把文本行分组

# batched 消耗文件迭代器,每次交出最多两行;转换后立即处理这批数据。
from itertools import batched
from pathlib import Path

path = Path("batches.txt")
path.write_text("20\n35\n45\n", encoding="utf-8")
with path.open(encoding="utf-8") as stream:
    for lines in batched(stream, 2):
        values = [int(line) for line in lines]
        print(values, sum(values))

得到 [20, 35] 55 和 [45] 45。文件要在这段消费期间保持打开;先从 with 中返回一个还没读取的文件生成器,再在外面消费,文件已经关闭。把消费放在 with 内,或者让生成器函数自己管理文件的整个使用过程。

笔记正文与全部题解 · Ctrl / ⌘ K