Python使用ExitStack读取多文件时未达末尾就关闭如何解决
问题根源
你遇到的截断问题和文件提前关闭无关,是Python内置zip()的默认设计:它会在传入的任意一个迭代器耗尽时立刻停止迭代。ExitStack的资源管理逻辑本身没有问题,它会等整个with代码块执行完成后才会统一关闭所有已打开的文件。你之所以会误以为文件被提前关闭,是因为zip触发迭代终止后循环直接退出,根本没走到长文件的剩余行读取逻辑,本质是迭代终止条件不符合需求,不是资源管理的bug。
解决方案
直接用标准库itertools.zip_longest替换内置zip即可。该函数会持续迭代直到所有传入的文件迭代器全部耗尽,短文件读完后的对应位置默认填充None,你也可以通过fillvalue参数自定义填充值,完全保留原方案多文件并行读取的性能优势,不会额外增加耗时。
修改后的代码如下:
from contextlib import ExitStack from itertools import zip_longest files_to_parse = [file1, file2, file3] with ExitStack() as stack: files = [stack.enter_context(open(i, "r")) for i in files_to_parse] # 如需自定义填充值,传入fillvalue参数即可,例:zip_longest(*files, fillvalue="") for rows in zip_longest(*files): for r in rows: if r is None: # 跳过已读完文件对应的填充值 continue # 写入原有的行处理逻辑
注意事项
- 如果待处理的文件本身存在空行,不要用
if not r这类宽泛的判断过滤填充值,否则会把真实空行也跳过,直接判断内容是否等于你设置的填充值即可 - 所有文件句柄依然由
ExitStack统一托管,不需要手动编写关闭逻辑,不会出现文件句柄泄漏问题 - 该方案的文件读取模式和原代码完全一致,能保持你之前测到的1/4耗时的性能表现
内容的提问来源于stack exchange,提问作者vwongjun
相关产品推荐
相关产品推荐

