直接 open().readlines() 会崩是因为它将整个文件一次性加载进内存,导致大文件触发 MemoryError;正确做法是用 for line in open() 配合 with 确保自动关闭,并用 rstrip("\n\r") 处理空行和换行符。

为什么直接 open().readlines() 会崩?
因为 readlines() 会把整个文件一次性加载进内存,几 GB 的日志或 CSV 文件直接触发 MemoryError。这不是代码写得不够“优雅”,是设计上就违背了流式处理原则——你不需要所有行同时在内存里,只需要当前这行。
真正该用的是迭代器语义:文件对象本身可迭代,且按需读取、逐行生成,内存占用恒定(约几十 KB),跟文件大小无关。
- ✅ 正确姿势:
for line in open("huge.log"): - ❌ 高危操作:
lines = open("huge.log").readlines() - ⚠️ 注意:必须配合
with确保自动关闭,否则句柄泄漏
with open() 里怎么跳过空行和首尾空白?
原始行常带 \n 和空格,直接处理容易出错(比如 if line == "xxx" 永远不成立)。别在循环里反复调 strip(),更别用正则预处理整行——性能损耗大,且破坏了“只读当前行”的轻量原则。
推荐在迭代时即时清理,保持逻辑清晰又不额外开销:
立即学习“Python免费学习笔记(深入)”;
with open("data.csv") as f:
for line in f:
line = line.rstrip("\n\r") # 只去行尾换行符,保留前导空格(如有业务意义)
if not line: # 跳过空行
continue
# 处理非空行
需要按块读取(比如每次 8KB)而不是逐行?
逐行适合文本日志、CSV;但遇到无换行分隔的二进制数据、或想控制 I/O 缓冲大小时,read(size) 更合适。注意:它不保证“刚好读到一行末尾”,可能把一行切成两半。
- 适用场景:
tar流解析、自定义协议包、避免小文件频繁系统调用 - 关键点:手动拼接不完整行,用
bytes.find(b"\n")或str.splitlines(keepends=True)辅助 - 别写
while True: chunk = f.read(8192); if not chunk: break—— 这会忽略最后一次不完整块的边界处理
编码错误(UnicodeDecodeError)怎么不中断流程?
日志文件混着 utf-8、gbk、甚至损坏字节很常见。用 errors="ignore" 或 errors="replace" 是最快解法,但会丢失信息;若需定位问题,建议捕获异常并记录偏移位置:
with open("messy.log", encoding="utf-8", errors="surrogateescape") as f:
for i, line in enumerate(f, 1):
try:
# 正常处理
process(line)
except UnicodeError as e:
print(f"Line {i} decode failed: {e}")
continue # 跳过坏行,继续下一行
注意 surrogateescape 模式能让解码失败的字节转成特殊 Unicode 字符,后续可逆向还原原始字节——这对调试乱码根源很有用,但多数脚本只需 ignore 就够。
真正麻烦的是混合编码且没 BOM 的文件,这时候靠猜不如先用 chardet 探测一次头部,再全局指定编码打开——但探测本身要读一部分内容,别在 for line in f 之前做全量探测,会破坏迭代器状态。


















