应避免用readlines()读大文件以防OOM,须改用for line in file流式处理;分批写入时需平衡内存与SQL效率,SQLite每批500–2000行,MySQL/PG可达5000–10000行并配事务;编码错误需按gbk、gb18030、utf-8-sig依次尝试,禁用errors='ignore';正则应逐行匹配而非全文加载。
用 readlines() 读大文件直接 OOM?别这么干
python 里直接 file.readlines() 会把整个文件加载进内存,一个 500mb 的 log.txt 很可能让进程爆掉——不是卡顿,是直接被系统 kill。这不是“慢”,是根本跑不起来。
真正该做的是流式逐行处理:
- 用
for line in file:迭代器方式,内存只存当前行 - 避免
file.read().split(' ')或list(file),它们等价于readlines() - 如果必须切块处理(比如每 1000 行一批),用
itertools.islice()配合循环,不缓存整块
分批写入数据库时批量太小,性能反而更差
常见误区是“既然是分批,那就每次插 1 行”,结果 IO 次数爆炸,INSERT INTO ... VALUES (...) 执行上万次,比单次插 10 万行还慢 10 倍。
关键在平衡内存占用和 SQL 效率:
- SQLite 推荐每批 500–2000 行,用
executemany()+ 参数化语句 - MySQL/PostgreSQL 可设到 5000–10000 行,配合事务包裹(
conn.begin()+commit()) - 注意字段里含
或'时,别手动拼 SQL——必须用参数占位符%s或?,否则注入+解析失败双杀
编码错误导致读到一半就停住或乱码
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0 这类报错,不是文件损坏,是你没告诉 Python 文件真实编码。Windows 记事本默认存的是 gbk 或 cp1252,不是 UTF-8。
稳妥做法是先探测再打开:
- 用
chardet.detect()粗略猜(注意它只看前 10KB,默认不准) - 更可靠:按常见编码依次尝试
open(... , encoding='gbk')、encoding='gb18030'、encoding='utf-8-sig'(带 BOM 的 UTF-8) - 遇到解码失败跳过该行?别用
errors='ignore',它会静默丢数据;改用errors='replace'至少留个 提示异常位置
正则匹配全文本导致 CPU 占满却无响应
写 re.findall(r'pattern', file.read()) 是典型陷阱:先读全量进内存,再一次性跑正则。对 GB 级文本,PCRE 引擎可能回溯爆炸,CPU 100% 卡死。
正确姿势是边读边匹配:
- 用
for line in file:逐行re.search(),匹配即处理,不累积 - 若需跨行匹配(如日志块),用缓冲区控制长度,比如保留最近 3 行,而不是
read(1024*1024)盲目切片 - 避免
.*和.+在大文本中无边界使用,换成更精确的否定字符集,比如[^\n]+
最常被绕开的其实是文件指针位置和编码 BOM 头——读完一批后 file.tell() 不一定等于字节数,而 utf-8-sig 会自动吞掉开头三个字节,这两点一错,后续分批就全偏了。


















