处理几百 MB 甚至 GB 级别的文件时,如果直接 f.read() 把整个文件内容读进内存,程序很容易因内存耗尽而崩溃。这一节就讲如何安全、高效地处理大文件。
逐行读取:处理文本文件的首选
当文件是文本格式(如日志、CSV、JSONL),最常见也最简单的做法是逐行读取——每次只把一行加载到内存,处理完就丢弃。
with open('large_file.log', 'r', encoding='utf-8') as f:
for line in f:
# 对每一行进行处理,比如提取关键信息
process(line)
for line in f本身就是一种迭代器,Python 会按缓冲区读取数据,不会一次性加载整个文件。- 如果需要保留行号,可以用
enumerate(f, start=1)。 - 对于 CSV 文件,可以直接用
csv.reader迭代:
import csv
with open('large.csv', 'r') as f:
reader = csv.reader(f)
for row in reader:
process(row)
分块读取:控制每次读取的字节数
对于二进制文件(图片、视频)或无法按行分割的文本,可以指定一个固定大小的块,循环读取直到文件末尾。
chunk_size = 1024 * 1024 # 1MB 一块
with open('large_file.bin', 'rb') as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
process(chunk)
- 块大小可以根据可用内存和业务需求调整,通常在 4KB~64MB 之间。
- 适合大文件复制、传输、哈希计算等场景。
利用生成器封装:让代码更整洁
可以把分块或逐行读取的逻辑封装成一个生成器,业务代码只需关心如何处理每一块数据。
def read_in_chunks(file_path, chunk_size=1024*1024):
with open(file_path, 'rb') as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
yield chunk
for chunk in read_in_chunks('big_data.bin'):
handle(chunk)
内存优化的额外技巧
- 及时释放变量:如果文件中有大量字符串或对象累积,用
del或在循环内复用变量,避免无用的引用。 - 优先使用迭代器:无论文件还是数据处理,能用迭代器就不用列表,避免在内存中产生中间副本。比如
sum(line.count('error') for line in f)比先构建列表再求和内存友好得多。 - 注意编码成本:读取文本时,如果不需要全部字符串内容,可以考虑只保留必要字段,或使用
bytes操作避免解码全部字符(仅在少数场景下适用)。
大文件处理的核心思想就是分而治之:让数据像水一样流过你的程序,而不是把整个池塘装进杯子里。养成逐行或分块处理的习惯,就能从容应对绝大部分大数据量场景,而不用担心内存溢出。