使用SXSSF创建大型.xls

时间:2016-03-24 08:08:07

标签: java excel xls xlsx jxls

我在使用SXSSF导出大型.xls时出现问题,我说大的意思是27列x 10 000行。 Excel文件是端点请求返回。我的行数有限 - 可以大3倍。

我使用模板引擎插入数据。

原始代码

public StreamingOutput createStreamedExcelReport(Map<String, Object> params, String templateName, String[] columnsToHide) throws Exception {
        try(InputStream is = ReportGenerator.class.getResourceAsStream(templateName)) {
            assert is != null;
            final Transformer transformer = PoiTransformer.createTransformer(is);
            AreaBuilder areaBuilder = new XlsCommentAreaBuilder(transformer);
            List<Area> xlsAreaList = areaBuilder.build();
            Area xlsArea = xlsAreaList.get(0);
            Context context = new PoiContext();
            for(Map.Entry<String, Object> entry : params.entrySet()) {
                context.putVar(entry.getKey(), entry.getValue());
            }
            xlsArea.applyAt(new CellRef("Sheet1!A1"), context);
            xlsArea.processFormulas();
            return new StreamingOutput() {
                @Override
                public void write(OutputStream out) throws IOException {
                    ((PoiTransformer) transformer).getWorkbook().write(out);
                }
            };
        }
    }

SXSSF

public StreamingOutput createStreamedExcelReport(Map<String, Object> params, String templateName, String[] columnsToHide) throws Exception {
        try(InputStream is = ReportGenerator.class.getResourceAsStream(templateName)) {
            assert is != null;
            Workbook workbook = WorkbookFactory.create(is);
            final PoiTransformer transformer = PoiTransformer.createSxssfTransformer(workbook);
            AreaBuilder areaBuilder = new XlsCommentAreaBuilder(transformer);
            List<Area> xlsAreaList = areaBuilder.build();
            Area xlsArea = xlsAreaList.get(0);
            Context context = new PoiContext();
            for(Map.Entry<String, Object> entry : params.entrySet()) {
                context.putVar(entry.getKey(), entry.getValue());
            }
            xlsArea.applyAt(new CellRef("Sheet1!A1"), context);
            xlsArea.processFormulas();
            return new StreamingOutput() {
                @Override
                public void write(OutputStream out) throws IOException {
                    transformer.getWorkbook().write(out);
                }
            };
        }
    }

导出运行了7分钟我停止了服务器 - 它太长了。可接受的时间是1分钟(最长2分钟)。大部分时间CPU使用率约为60-80%,内存使用量不变。我也尝试输出40行 - 花了10秒钟。

也许我的功能需要优化。

其他问题是我要插入功能。在原始代码中,函数被替换为值。在SXSSF版本中,它们不是。

1 个答案:

答案 0 :(得分:0)

我建议您在此时禁用公式处理,因为支持SXSSF版本的公式有限且内存消耗可能过高。在未来的JXLS版本中,可以改进公式支持。

所以只需删除xlsArea.processFormulas()来电并添加

即可

context.getConfig().setIsFormulaProcessingRequired(false);

禁用单元格引用的跟踪(如Jxls doc所示)并查看它是否有效。

另请注意,如果您使用SXSSF,模板和最终报告应采用.xlsx格式。