如何快速读取Zip压缩包内Excel文件并高效完成读写操作?
压缩包内Excel读写性能优化方案
针对你这段循环处理压缩包内Excel并写入结果的代码,以下是几个直击性能瓶颈的优化方案:
1. 避免重复解析同一个Excel文件
原代码中对同一个压缩包内的Excel文件调用两次pd.read_excel(分别读取Sheet1和Sheet2),这会导致文件被重复解析两次,浪费IO和计算资源。改用pd.ExcelFile一次性加载文件,再读取多个Sheet,能直接减少一半的文件解析开销:
# 优化后:一次性加载Excel文件,再读取多个Sheet with pd.ExcelFile(xlfile_pro) as xls_pro: sheet1_pro = pd.read_excel(xls_pro, sheet_name='Sheet1') sheet2_pro = pd.read_excel(xls_pro, sheet_name='Sheet2') with pd.ExcelFile(xlfile_ref) as xls_ref: sheet1_ref = pd.read_excel(xls_ref, sheet_name='Sheet1') sheet2_ref = pd.read_excel(xls_ref, sheet_name='sheet2')
2. 只读取需要的目标行,拒绝全量加载
你只需要计算特定行(Row1、Row29)的求和值,完全没必要加载整个Sheet的所有数据。通过精准定位目标行并只读取这些行,能大幅减少内存占用和读取时间:
如果目标行是按行名(index label)定位
def get_target_row(xls_file, sheet_name, target_row_label): # 先读取行索引,定位目标行的位置 df_index = pd.read_excel(xls_file, sheet_name=sheet_name, usecols=[0], index_col=0) target_row_pos = df_index.index.get_loc(target_row_label) + 2 # 转换为Excel行号(从1开始) # 只读取目标行 return pd.read_excel(xls_file, sheet_name=sheet_name, skiprows=target_row_pos-1, nrows=1, index_col=0) # 使用示例 with pd.ExcelFile(xlfile_pro) as xls_pro: sheet2_row1 = get_target_row(xls_pro, 'Sheet2', 'Row 1') sheet1_row29 = get_target_row(xls_pro, 'Sheet1', 'Row29') with pd.ExcelFile(xlfile_ref) as xls_ref: sheet2_ref_row1 = get_target_row(xls_ref, 'Sheet2', 'Row 1') sheet1_ref_row29 = get_target_row(xls_ref, 'Sheet1', 'Row29') # 计算逻辑不变 x = (sheet2_row1.sum().iloc[0] - sheet2_ref_row1.sum().iloc[0]) * -1 y = (sheet1_row29.sum().iloc[0] - sheet1_ref_row29.sum().iloc[0]) * 0.7 / 1000 * -1
如果目标行是按行号(比如第1行、第29行)
直接跳过无关行,只读取目标行:
def get_row_by_number(xls_file, sheet_name, row_num): # row_num为Excel中的行号(从1开始) return pd.read_excel(xls_file, sheet_name=sheet_name, skiprows=row_num-1, nrows=1, index_col=0)
3. 批量写入结果,避免频繁文件IO
原代码每次循环都打开、修改、保存Excel文件,这是最大的性能杀手之一。应该先把所有循环的计算结果收集到一个DataFrame中,最后一次性写入文件,把多次IO操作减少为一次:
# 提前初始化结果DataFrame(根据你的需求定义结构) df_results = pd.DataFrame(index=['Specific Row'], columns=[f'Col{i}' for i in range(4)]) with ZipFile(Project_path) as zip_file_pro , ZipFile(Reference_path) as zip_file_ref: for fn_pro,(member_pro , member_ref) in enumerate(zip(zip_file_pro.namelist(),zip_file_ref.namelist())): # ... 前面的读取和计算逻辑 ... # 将当前循环的结果存入df_results df_results.loc['Specific Row', df_results.columns[3]] = (x - y) * 1 # 循环结束后,一次性写入Excel project_exl = load_workbook(file_path) with pd.ExcelWriter(file_path, engine='openpyxl') as Write_result: Write_result.book = project_exl Write_result.sheets = {ws.title: ws for ws in project_exl.worksheets} df_results.to_excel(Write_result, sheet_name='Result_1', index=False, header=False, startrow=12, startcol=3) # 使用with上下文管理器会自动关闭并保存,无需手动调用close()和save()
4. 更换更高效的Excel引擎
Pandas的read_excel支持多种引擎,针对.xlsx文件,pyxlsb(处理二进制格式xlsx)的读取速度比默认的openpyxl快很多。先安装依赖:
pip install pyxlsb
然后在读取时指定引擎:
sheet1_pro = pd.read_excel(xls_pro, sheet_name='Sheet1', engine='pyxlsb')
5. 并行处理(适合大量Excel文件的场景)
如果压缩包内有几十上百个Excel文件,可以用多线程并行处理,利用CPU多核提升效率:
from concurrent.futures import ThreadPoolExecutor def process_single_pair(member_pro, member_ref): # 每个线程单独打开Zip文件(避免线程安全问题) with ZipFile(Project_path) as zip_file_pro, ZipFile(Reference_path) as zip_file_ref: xlfile_pro = zip_file_pro.open(member_pro) xlfile_ref = zip_file_ref.open(member_ref) # ... 读取目标行、计算逻辑 ... return (x - y) * 1 # 获取两个压缩包的成员列表 with ZipFile(Project_path) as zip_file_pro, ZipFile(Reference_path) as zip_file_ref: members_pro = zip_file_pro.namelist() members_ref = zip_file_ref.namelist() # 并行处理,max_workers根据CPU核心数调整 with ThreadPoolExecutor(max_workers=4) as executor: all_results = list(executor.map(process_single_pair, members_pro, members_ref)) # 将结果批量填充到df_results中 df_results.loc['Specific Row', df_results.columns[3]] = all_results[-1] # 根据你的需求调整赋值逻辑
内容的提问来源于stack exchange,提问作者armhels
相关产品推荐
相关产品推荐

