read() 无参数会一次性加载整个文件进内存,导致大文件读取时内存爆满;正确做法是用 with open + yield 逐行生成器,避免缓存全文。

为什么用 read() 读大文件会爆内存
因为 read() 无参数调用时,会把整个文件内容一次性加载进内存——文件多大,内存就吃多大。1GB 文件 → 至少 1GB 内存占用;遇到几十GB 日志或导出数据,Python 进程大概率被系统 OOM killer 杀掉,Linux 下直接静默退出,Windows 下卡死或闪退。
yield 生成器逐行读取的正确写法
核心是让函数返回一个生成器对象,每次只 yield 一行,不缓存全文。注意三点:
- 必须用
with open(...)确保文件句柄及时关闭,不能在生成器外提前close() -
yield后不要做耗时处理(如 JSON 解析、正则匹配),否则会阻塞迭代流;复杂逻辑应交给调用方 - 生成器对象只能遍历一次,重复使用需重新调用函数
示例:
def read_large_file(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
for line in f: # 文件对象本身是迭代器,无需 readlines()
yield line.rstrip('\n')
<h1>正确用法:for 循环自动触发 next()</h1><p>for line in read_large_file('access.log'):
if '404' in line:
print(line)</p><h1>错误用法:转成 list 就失去惰性优势</h1><h1>lines = list(read_large_file('access.log')) # 全部加载进内存!</h1><p></p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill9965" title="macOS UI 自动化技能包 —— 用 Python 控制你的 Mac"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20dbae7c507.jpg" alt="macOS UI 自动化技能包 —— 用 Python 控制你的 Mac" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill9965" title="macOS UI 自动化技能包 —— 用 Python 控制你的 Mac" class="overflowclass">macOS UI 自动化技能包 —— 用 Python 控制你的 Mac</a>
<p class="overflowclass">让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript
系统要求
macOS 14+ (Sonoma)
Python 3.9+
需要开启:辅助功能 + 屏幕录制权限</p>
</div>
<a rel="nofollow" href="/xiazai/skill9965" title="macOS UI 自动化技能包 —— 用 Python 控制你的 Mac" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
处理非文本大文件(如 CSV、JSON)时别硬套 yield line
逐行 yield 是最通用的起点,但实际结构化数据有更优解:
- CSV 文件优先用
pandas.read_csv(chunksize=N),它内部已封装分块逻辑,支持 dtype 控制、缺失值处理等,比手写生成器更健壮 - 超大 JSON 文件别用
json.load(),改用ijson.parse()或ijson.items()流式提取路径节点,例如ijson.items(f, 'records.item') - 二进制大文件(如视频、模型权重)不适合按行 yield,应改用
file.read(chunk_size)分块读取,chunk_size建议设为 8192 或 65536
生成器不是万能解药:容易被忽略的陷阱
生成器解决的是「内存峰值」问题,但不会自动解决其它问题:
- 文件编码错误仍会抛
UnicodeDecodeError,必须显式指定encoding参数,或用errors='ignore'/'replace' - 如果每行处理逻辑很重(比如调用外部 API、写数据库),生成器只是把内存压力转成了时间压力,可能拖慢整体吞吐
- 调试困难:无法像列表一样索引访问某一行,
next(g, None)只能向前取,不能回退 - 多线程下不能共享同一个生成器对象,每个线程需独立实例
真正关键的判断点在于:你是否需要随机访问、重复遍历、或强一致性校验——如果有,生成器就不适合,得换 mmap 或临时落盘分片。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










