Java加载XLSM格式Excel耗时过长,能否仅读取最后90行优化加载速度?
Java实现部分加载XLSM的方案
你当前使用的是Apache POI的用户模式(UserModel),这种机制会将整个Excel文件的所有内容加载到内存中构建完整的工作簿对象,所以不管你后续实际读取几行数据,加载阶段都必须处理全文件,35秒的加载耗时就是这个原因导致的。
Java完全支持部分加载XLSM格式文件,优先推荐以下两种方案:
方案1:使用Alibaba EasyExcel(推荐,开发成本极低)
EasyExcel底层基于POI的事件模式封装,支持按需读取行,不需要加载全量文件,针对你的场景只需要读取前3行表头(你代码中用到的malzeme、kaynak、endeks三行)+ 最后90行数据即可,加载耗时可以降到5秒以内,原生支持XLSM格式。
核心代码逻辑示例:
// 定义数据接收实体 @Data public class ExcelRowData { // 第4列是日期,对应POI索引为3 @ExcelProperty(index = 3) private LocalDateTime tarih; // 用Map接收900个动态列的内容,key为列索引 @ExcelProperty(unmatched = true) private Map<Integer, Object> columnValues; } // 读取逻辑 public void readPartialXLSM(String filePath) throws IOException { // 第一步:读取前4行表头数据(POI行索引从0开始,对应你原代码的行1、2、3为索引1、2、3) List<Map<Integer, Object>> headerRows = EasyExcel.read(filePath).sheet(0) .headRowNumber(0) .limit(4) .doReadSync(); Map<Integer, Object> malzeme = headerRows.get(1); Map<Integer, Object> kaynak = headerRows.get(2); Map<Integer, Object> endeks = headerRows.get(3); // 第二步:快速获取文件总行数(事件模式只扫描行索引,不加载单元格内容,耗时毫秒级) ExcelReader excelReader = EasyExcel.read(filePath).build(); ReadSheet readSheet = EasyExcel.readSheet(0).build(); excelReader.read(readSheet); int totalRowNum = readSheet.getSheet().getLastRowNum(); excelReader.close(); // 第三步:只读取最后90行数据 List<ExcelRowData> last90Rows = EasyExcel.read(filePath).sheet(0) .headRowNumber(totalRowNum - 90) // 跳过前面不需要的行 .limit(90) .head(ExcelRowData.class) .doReadSync(); // 后续拼接SQL、写入文件的逻辑和你原有逻辑完全一致即可 }
方案2:原生Apache POI事件模式
如果不想引入第三方依赖,可以自己实现POI的XSSF事件解析逻辑,监听行读取事件,跳过不需要的行,只解析前3行和最后90行的内容即可,性能和EasyExcel相当,只是开发成本稍高。
其他语言实现可选方案
如果考虑用Python实现,用openpyxl的只读模式也可以快速实现部分加载,代码更简洁:
from openpyxl import load_workbook # 只读模式打开XLSM文件,不加载全量内容,keep_vba参数支持XLSM格式 wb = load_workbook('你的文件路径.xlsm', read_only=True, keep_vba=True) sheet = wb[wb.sheetnames[0]] max_row = sheet.max_row # 读取前3行表头(openpyxl行索引从1开始,对应你原代码的行1、2、3) malzeme = sheet[2] kaynak = sheet[3] endeks = sheet[4] # 只读取最后90行 last_90_rows = sheet.iter_rows(min_row=max_row - 89, max_row=max_row) # 后续处理数据拼接SQL即可
额外优化建议
你当前直接拼接SQL字符串的写法存在SQL注入风险,后续建议改成JDBC预编译PreparedStatement批量插入,性能和安全性都更高。
内容的提问来源于stack exchange,提问作者Mykyusuf
相关产品推荐
相关产品推荐

