2016-03-24 100 views
0

我有用SXSSF導出大型.xls的問題,我說的意思是27列x 100 000行。 Excel文件在端點請求上返回。我有限的行數 - 它可以是3倍大。使用SXSSF創建大型.xls

我正在使用模板引擎插入數據。

原始代碼

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版本中它們不是。

回答

0

我建議您此時禁用公式處理,因爲公式支持SXSSF版本是有限的,並且內存消耗可能太高。在未來的JXLS發佈中,公式支持可能會得到改進。

所以只是刪除xlsArea.processFormulas()呼叫,並添加

context.getConfig().setIsFormulaProcessingRequired(false);

禁用單元格引用的跟蹤(如圖Jxls doc),看看它是否工作。

另請注意,如果您使用SXSSF,則模板和最終報告預計將採用.xlsx格式。

+0

不幸的是,它沒有幫助。它在沒有公式處理的情況下工作,但仍然比非SXSSF版本慢。 – hya

+0

你玩過SXSSF的Window Size選項嗎?它對性能有影響嗎?我的理解是,SXSSF與非SXSSF的總體表現可能不會更好。但真正的好處是消除了內存限制。 –

+0

在這種情況下,內存限制不是問題。 3000行將輸出〜1分鐘,我需要處理更多。數據集將會增長,因此需要性能提升。其他解決方案?也許一些其他語言的腳本? – hya