for line in open()是最稳妥起点,因其利用文件迭代器按行读取,内存恒定几KB;而readlines()一次性加载全文件易OOM,且list(f)和read().splitlines()同属危险操作。

for line in open() 是最稳妥的起点,不是因为它“快”,而是它让内存占用恒定在几 KB——只要你没遇到单行 200MB 的 base64 字段。
为什么 for line in f 比 f.readlines() 安全得多
文件对象本身是迭代器,for line in f 底层调用 f.__next__(),每次只把一行(直到下一个 \n)载入内存,不缓存、不预读、不构建列表。f.readlines() 则会一次性把所有行指针塞进 list,1GB 日志可能吃掉 3–4GB 内存(字符串开销 + 指针)。
常见错误现象:list(f) 看似简洁,行为和 f.readlines() 完全一致,只是更隐蔽;f.read().splitlines() 同样全量加载,毫无优势。
- 必须搭配
with open(...),否则异常时文件句柄不释放 - 每行末尾自带
\n或\r\n,建议用line.rstrip('\r\n')清理,比strip()快 15%–20% - 含 BOM 的 UTF-8 文件(如 Windows 记事本保存),用
encoding='utf-8-sig'自动剥离首行\ufeff - 跳过空行或注释:直接写
if not line.strip() or line.startswith('#'): continue,别提前filter()
f.read(size) 什么时候必须上
当文件里存在超长无换行内容(比如嵌入式 JSON、base64 块)、或混有二进制垃圾、或你根本不确定换行结构时,for line in f 会卡死甚至 OOM——这时只能切回字节粒度控制。
关键不是“快”,而是能硬性限制单次内存峰值。例如某行实际 150MB,for 循环照样把它全拉进来;而 f.read(1048576)(1MB)永远只拿这么多。
立即学习“Python免费学习笔记(深入)”;
- 必须用
mode='rb'打开,避免编码解析中断风险 - size 推荐设为
65536(64KB)或1048576(1MB),对多数文件系统更友好 - UTF-8 中文可能被截断:读完一块后,检查末尾 1–3 字节是否构成完整字符,常用策略是预留末尾字节与下一块拼接再解码
- 别用
io.TextIOWrapper包装来“自动处理边界”——它会丧失字节数精确控制能力
mmap 只适合随机访问,别用来顺序读
mmap 不省物理内存,只是把文件映射成虚拟地址空间;它适合反复回溯、多进程共享、或需按偏移快速查找的场景,比如解析数据库索引、校验 checksum、或 mm.find(b'ERROR') 这种 grep 式搜索。
- Windows 下必须用
r+b或rb打开,且用完必须调mm.close(),否则资源泄漏 - 不能用在 NFS 或某些网络文件系统上,依赖底层支持
- 对纯顺序扫描毫无优势,反而增加初始化开销;别为了“听起来高级”而滥用
-
mm[1024:2048]直接拿到字节,但后续解析仍需你自己处理编码或结构(比如用struct.unpack())
mmap 解决的是“随机访问”问题。选错前提,再优化也白搭。


















