Python内存高效读取.txt文件及后续合并排序的方案咨询
原生Python的字符串、列表对象都带有额外的元数据开销,把所有文本行全部加载为列表格式后,内存占用达到原始文件的8~10倍属于正常现象。不需要全量加载数据到内存就能实现合并排序的优化方案如下:
方案1:分文件排序+堆合并(内存占用最低,适合总数据量远大于可用内存的场景)
核心逻辑是先单独对每个小文件排序,再用heapq.merge合并多个有序流,合并过程不需要加载全量数据,内存峰值仅等于单个最大文件的加载开销:
import csv import heapq from operator import itemgetter from tempfile import NamedTemporaryFile import os file_paths = [ '../Results/DIMP_1120.txt', '../Results/DIMP_1121.txt', '../Results/DIMP_1122.txt' ] sorted_temp_files = [] # 逐个处理单个文件,排序后写入临时文件 for path in file_paths: with open(path, 'r', encoding='utf-8') as f: rows = list(csv.reader(f, delimiter='|')) # 单个文件内部排序 rows.sort(key=itemgetter(0)) # 写入临时文件 temp_f = NamedTemporaryFile(mode='w+', encoding='utf-8', delete=False) writer = csv.writer(temp_f, delimiter='|') writer.writerows(rows) temp_f.close() sorted_temp_files.append(temp_f.name) # 立即释放当前文件的内存占用 del rows # 定义生成器逐行读取有序临时文件,不加载全量数据 def read_sorted_file(path): with open(path, 'r', encoding='utf-8') as f: yield from csv.reader(f, delimiter='|') # 合并所有有序流,返回的是迭代器,全程不加载全量数据 sorted_streams = [read_sorted_file(path) for path in sorted_temp_files] big_sorted_iter = heapq.merge(*sorted_streams, key=itemgetter(0)) # 后续可直接遍历迭代器处理数据,无需转列表;如果确实需要全量列表再执行list(big_sorted_iter) # 清理临时文件 for path in sorted_temp_files: os.unlink(path)
如果后续业务可以逐行处理排序后的数据,不需要把全量结果存在内存里,这个方案的内存占用可以降到原来的1/3甚至更低。
方案2:Pandas优化存储(代码更简洁,适合中等规模数据)
Pandas内部对字符串、数值的存储优化远好于原生Python列表,相同数据量的内存占用仅为原生列表的1/3~1/2:
import pandas as pd file_paths = [ '../Results/DIMP_1120.txt', '../Results/DIMP_1121.txt', '../Results/DIMP_1122.txt' ] df_list = [] for path in file_paths: # 可根据可用内存调整chunksize,单个文件过大时可分块读取 df = pd.read_csv(path, sep='|', header=None) df_list.append(df) # 合并后按首列排序 full_df = pd.concat(df_list, ignore_index=True) sorted_df = full_df.sort_values(by=0, kind='mergesort') # 需要转原生列表时执行sorted_df.values.tolist()即可
方案3:最小改动优化原生逻辑(不想改整体流程时使用)
如果不想调整现有合并排序的逻辑,只做最小改动就能降低30%~50%内存占用:
- 把每行存储格式从列表改成元组,元组的内存开销比列表低20%左右
- 首列如果是数值类型,直接转成整数/浮点数存储,比字符串省大量内存
示例代码:
import csv from operator import itemgetter def read_dimp_file(path): with open(path, 'r') as f: # 转元组,首列转整数减少内存开销 return [ (int(row[0]), *row[1:]) for row in csv.reader(f, delimiter="|") ] DIMP_1120 = read_dimp_file('../Results/DIMP_1120.txt') DIMP_1121 = read_dimp_file('../Results/DIMP_1121.txt') DIMP_1122 = read_dimp_file('../Results/DIMP_1122.txt') big_list = DIMP_1120 + DIMP_1121 + DIMP_1122 big_list = sorted(big_list, key=itemgetter(0))
内容的提问来源于stack exchange,提问作者Tanai Goncalves
相关产品推荐
相关产品推荐

