Python处理大Excel文件:openpyxl性能瓶颈与xlrd替代方案
本文针对Python处理大型Excel文件时openpyxl读取缓慢的问题,通过对比测试分析了openpyxl与xlrd的性能差异。指出openpyxl基于遍历的读取机制导致大文件处理耗时显著增加,而xlrd采用类似数组的下标访问方式,读取速度更稳定。文章提供了具体的性能测试代码、结果对比以及一个用于监控函数运行时间的装饰器示例,为处理百万行级Excel数据提供了实用的技术参考。
Python大Excel文件性能优化方案
为了节省篇幅,这里直接展示核心代码与测试过程。
Talk is cheap, show me the code.
from openpyxl import Workbook
from openpyxl.utils import get_column_letter
from openpyxl import load_workbook
import time
wb = load_workbook("E:/a.xlsx", read_only=True)
sh = wb["Sheet"]
# rowItem = {}
# for j in range(1,2000):
# for i in range(1, 30):
# rowItem[get_column_letter(i)] = i
# sh.append(rowItem)
# wb.save("E:/a.xlsx")
t0 = time.time()
print(sh['V500'].value)
t1 = time.time()
print("openpyxl所用时间:", str(t1-t0))
import xlrd
xlsPath = "E:/a.xlsx"
WorkBook = xlrd.open_workbook(xlsPath)
sh = WorkBook.sheet_by_name("Sheet")
t0 = time.time()
print(sh.cell(499,22).value)
t1 = time.time()
print("xlrd所用时间:", str(t1-t0))
以下是具体的测试结果数据:
22
openpyxl所用时间: 0.44217610359191895
23.0
xlrd所用时间: 0.0010063648223876953
openpyxl与xlrd性能对比分析
测试结论分析
openpyxl在处理大文件时的主要瓶颈在于读取速度。针对这一痛点,可以考虑使用xlrd库进行替代,详细的测试数据与分析将在下文展开。
之所以没有直接采用xlwt配合xlrd的方案,是因为xlwt仅支持Excel 2003及更早版本,其最大行数限制为65536行,无法满足大规模数据需求。相比之下,openpyxl支持Excel 2007+格式,可处理约一百多万行的数据,因此在行数要求较高时更具优势。
在开发工具的过程中遇到了这一性能问题。起初使用xlwt和xlrd组合,当数据行数超过限制后,被迫切换至使用openpyxl处理Excel 2007格式的文件。原本测试不到三万行的数据,使用openpyxl耗时数分钟,具体时长未精确记录。通过添加函数运行时间监视器后,确认性能瓶颈主要出现在数据读取阶段。
读取机制差异与性能瓶颈原因
关于性能差异的原因推测如下:
openpyxl在根据行号和列号读取数据时,底层机制是从第一行第一列开始遍历,直到定位到指定的行号和列号。因此,目标单元格的位置越靠后,遍历次数越多,读取速度越慢(即便从第一个有数据的单元格开始计算也是如此)。而xlrd的读取机制类似于数组访问,通过下标直接定位到内存中的对应地址,因此无论Excel文件的总数据量大小如何,读取特定单元格的速度基本保持不变。
潜在限制与注意事项
遗留问题与注意事项
虽然xlwt写入仅限制在65536行,但需留意xlrd读取时是否也存在类似的行数限制,即超过该数量的数据可能会导致读取错误。
在本案例中,由于业务逻辑是将多表数据合并生成单表数据,生成逻辑大致为Na*Nb的形式。因此,实际读取的源数据量并不大,但生成的数据量巨大。基于这种场景,上述关于读取速度的问题对整体性能影响较小,可以暂时忽略。
另外,有观点指出xlrd在读取xlsx格式文件时偶尔会出现兼容性问题。由于目前尚未进行专门测试且当前使用正常,该问题暂时未被深入排查。
函数运行时间监控工具
最后,分享一个用于监控函数运行时间的Python装饰器代码:
import time
from functools import wraps
def fn_timer(function):
@wraps(function)
def function_timer(*args, **kwargs):
t0 = time.time()
result = function(*args, **kwargs)
t1 = time.time()
print ("Total time running %s: %s seconds" %
(function.__name__, str(t1-t0))
)
return result
return function_timer
使用方法非常简单,只需在需要监控执行时间的函数定义上方添加@fn_timer装饰器即可。
以上关于解决Python执行较大Excel文件时openpyxl性能缓慢问题的内容分享给大家,希望能为遇到类似问题的开发者提供参考。如果觉得有用,欢迎支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













