大文件读取应避免readlines(),改用逐行迭代或分块读取;需指定encoding和errors处理编码异常;二进制文件用'rb'模式;linecache仅适用于随机查少数行。

大文件读取时内存爆掉,是因为用了 readlines()
Python 默认的 readlines() 会把整个文件加载进内存,哪怕只是想统计行数或过滤几行。1GB 的日志文件可能瞬间吃光 4GB 内存——这不是代码写错了,是调用方式不对。
真正安全的做法是让 Python 按需拉取,而不是“一口吞”。核心就两条路:逐行迭代(适合文本行结构清晰)、分块读取(适合二进制或无固定换行符的场景)。
-
for line in open(...)是最轻量的逐行方案,底层走迭代器,内存占用≈单行长度 - 别用
readlines()或read().split('\n'),它们都强制载入全部内容 - 如果文件含超长行(比如单行几百MB的 JSON Line 变体),逐行也不安全,得切回分块
逐行处理必须加 encoding 和异常跳过
生产环境的大文件常混着编码错误(比如日志里插了二进制 dump、Windows 与 Linux 换行符交错)。不处理就会在某一行直接抛 UnicodeDecodeError 中断整个流程。
with open('access.log', 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
if not line.strip():
continue
# 处理逻辑
process_line(line)-
errors='ignore'跳过非法字节,errors='replace'用 替代,按需选 -
strip()判空比len(line) > 0更稳妥,能干掉纯空白行和 \r\n\r\n 类型脏数据 - 别在循环里反复打开/关闭文件,
with块外操作会导致ValueError: I/O operation on closed file
分块读取要用 read(size),不是 readline()
当文件没有明确换行(如 protobuf 二进制流、拼接的 gzip 块、加密 payload),readline() 会一直卡住直到遇到 \n——这等于失效。此时必须手动控制缓冲区大小。
立即学习“Python免费学习笔记(深入)”;
def read_in_chunks(file_obj, chunk_size=8192):
while True:
data = file_obj.read(chunk_size)
if not data:
break
yield data
with open('data.bin', 'rb') as f:
for chunk in read_in_chunks(f, 65536): # 每次读 64KB
process_chunk(chunk)
-
chunk_size不是越大越好:32KB ~ 128KB 是多数 SSD 的友好区间;超过 1MB 容易触发 OS 缓存抖动 - 二进制文件务必用
'rb'模式,否则 Windows 下可能误截断 \x1A - 若需按记录解析(如每条 1024 字节定长),别在 chunk 边界硬切,要缓存跨块的残余字节
linecache 只适合随机查几行,千万别用来遍历
有人看到文档说 linecache.getline(filename, n) 能快速取第 n 行,就以为能用它写个 for 循环遍历——这是典型误用。它内部会为每个文件维护一个全局缓存字典,连续调用 getline 实际上把整文件又悄悄载入内存了。
-
linecache的唯一合理场景:调试时临时查某几行,比如日志报错说 “line 1234567”,你只想看那一行 - 它不释放缓存,多次调用不同文件会导致内存只增不减
- 真要随机访问大文件的多行,应该先用
mmap+ 扫描换行符建索引,或者转成数据库(SQLite + FTS5)
逐行和分块不是非此即彼的选择,关键看数据结构是否“可流式切割”。很多失败案例,其实卡在没意识到某类日志既不是纯文本也不是纯二进制——比如带嵌套 JSON 的混合日志,得先分块识别边界,再对每块做 JSON 流解析。










