itertools.zip_longest是处理不等长序列并行迭代的标准解法,通过fillvalue参数填充缺失值,默认为None;与zip不同,它会持续到最长序列耗尽,避免数据丢失。

用 itertools.zip_longest 实现按行交织合并
直接用 zip_longest 是最简洁、内存友好的方式,尤其适合大文件。它会从每个文件逐行读取,按索引对齐输出,缺失行用指定填充值(如空字符串)补位。
常见错误是误用 zip:一旦某个文件提前结束,zip 就立即停止,导致后续文件的剩余行被丢弃。
- 必须用
itertools.zip_longest,不是zip - 填充值设为
''(空字符串),避免拼接时多出意外字符 - 每个文件要用
open(...)单独打开,不能复用同一个 file object - 记得用
strip()清理换行符,否则交织后会出现空行
from itertools import zip_longest
<p>files = ['a.txt', 'b.txt', 'c.txt']
file_handlers = [open(f) for f in files]
try:
for lines in zip_longest(*file_handlers, fillvalue=''):
merged_line = ''.join(line.rstrip('\n') for line in lines)
print(merged_line)
finally:
for f in file_handlers:
f.close()
需要严格按“轮询顺序”而非对齐行号?用 itertools.cycle + next
如果目标是“先取 a.txt 第 1 行,再取 b.txt 第 1 行,再 c.txt 第 1 行,然后回到 a.txt 第 2 行……”,即轮询式取行(类似 round-robin),那 zip_longest 不适用——它强制按行号对齐。
这时得手动控制读取节奏,核心是:把每个文件转成迭代器,用 cycle 轮流调用 next(),捕获 StopIteration 后剔除已耗尽的迭代器。
立即学习“Python免费学习笔记(深入)”;
- 不能预先
list(file),否则失去流式读取优势,大文件会爆内存 - 每次
next()前必须用try/except StopIteration捕获,不能靠返回值判断 -
itertools.cycle在这里只是辅助调度,真正驱动的是显式的next()调用
from itertools import cycle
<p>files = ['a.txt', 'b.txt', 'c.txt']
iters = [iter(open(f)) for f in files]</p><p>while iters:
next_iters = []
for it in iters:
try:
line = next(it).rstrip('\n')
print(line)
next_iters.append(it)
except StopIteration:
pass # 文件读完,不加入下一轮
iters = next_iters
写入文件时遇到 UnicodeEncodeError: 'gbk' codec can't encode character
Windows 默认用 gbk 编码打开文件,但文本含中文、emoji 或特殊符号时大概率报错。这不是数据问题,是编码声明缺失。
- 所有
open()调用必须显式加encoding='utf-8' - 写入目标文件也要加
encoding='utf-8',且推荐加newline=''避免 Windows 下额外空行 - 不要依赖
sys.getdefaultencoding(),它和文件 I/O 编码无关
正确写法:open('out.txt', 'w', encoding='utf-8', newline='')
为什么不用 pandas.concat 或一次性 readlines()?
因为这两者都要求把全部内容载入内存。三个 100MB 的文件,readlines() 可能吃掉 1GB+ 内存,还附带每行对象的 Python 开销;pandas 更重,且默认按列对齐,不是按行交织。
- 交织合并本质是流式操作,应保持 O(1) 内存占用(只存当前行)
-
itertools工具链天然惰性,不触发实际读取直到next() - 若真需后期处理(比如过滤、转换),应在
for循环内单行处理,而不是攒全量再 map
真正容易被忽略的是文件关闭时机——用 with 语句虽安全,但多个文件时嵌套太深;手动 close() 又容易漏。更稳的方式是用 contextlib.ExitStack,不过对简单脚本,try/finally 已足够。


















