直接用 open().read() 读大文件会因一次性分配全部内存导致 OOM;应使用 iter(partial(f.read, chunk_size), b'') 构造生成器分块读取,配合 with 确保资源释放,chunk_size 推荐 4KB–64KB。

为什么不能直接用 open().read() 读大文件
内存会爆。比如一个 4GB 的固件镜像,open('firmware.bin', 'rb').read() 会尝试一次性分配 4GB 连续内存,Python 进程大概率被系统 OOM killer 干掉,或者卡死在 swap 里。生成器不是“语法糖”,它是把“读多少、处理多少”这件事从语言层面固化下来。
用 iter() + functools.partial 构造安全块读取生成器
核心是绕过手动写 while True 和 break 的易错逻辑。标准库提供了更健壮的构造方式:
from functools import partial
<p>def read_in_chunks(filepath, chunk_size=8192):
with open(filepath, 'rb') as f:</p><h1>iter(callable, sentinel):反复调用 partial(f.read, chunk_size),直到返回 b''</h1><pre class="brush:php;toolbar:false;"> for chunk in iter(partial(f.read, chunk_size), b''):
yield chunk
-
chunk_size建议设为 4096–65536(4KB–64KB),太小增加系统调用开销,太大削弱流式优势 - 必须用
b''作哨兵值(sentinel),因为f.read(n)在 EOF 时返回空 bytes,不是None - 不要在生成器外保留
f引用——with确保文件句柄及时释放,否则 Windows 下可能报PermissionError
遇到 mmap 或 zipfile 等特殊格式怎么办
生成器只解决“读取”,不解决“解析”。如果文件是 zip 包或需要随机访问(如 ELF header 跳转),别硬套块读:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 对
.zip文件,用zipfile.ZipFile的open()方法获取子文件的类文件对象,再套上面的生成器 - 对需要 seek 的场景(如解析 FAT32 分区镜像),改用
mmap.mmap,它支持[:]切片和find(),但注意mmap仍会映射整个文件到虚拟内存——大文件慎用 - 若块内需校验(如 CRC32),别等全部读完再算:在
for chunk in read_in_chunks(...)循环里累积更新crc32(chunk, crc)
调试时怎么确认真正在流式读取
最直接的办法是监控进程 RSS 内存占用,而不是看代码有没有 yield:
- Linux/macOS 下用
ps -o pid,rss,comm= -p $(pgrep -f "python.*your_script")每秒刷新一次 - 如果 RSS 始终稳定在几 MB(而非随文件大小线性增长),说明生效
- 加一句
print(f"Read {len(chunk)} bytes")到生成器循环里,观察是否持续输出——卡住或只打一行,大概率是文件路径错、权限不足,或chunk_size设成了 0
真正容易被忽略的是错误传播:生成器内部的 IOError(如磁盘拔出)不会立即抛出,而是在第一次 next() 或 for 迭代时才触发。别假设“调用了生成器就等于文件已打开”。

















