You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 01:06:01