带JXLS的SXSSF变压器2

我想在JXLS上使用SXSSF变压器。 我试图写我的模板,我不会得到“试图写入已经写入磁盘的范围内的行”exception。 模板捕获已知列(例如“HEADER 0”)和未知列(以“_dynamic”结尾的列)。 dynamic列的数量因运行而异。

如果我configurationSXSSF窗口大于行数,我没有问题。 如果我把窗口设置为less于行数,那么我得到“试图写一行…”exception。 但是,在这两种情况下,工作簿都已创build。 在足够的窗口大小的情况下,结果中包含已知列(“HEADER 0”)。 在窗口大小不足的情况下,已知的列值将在结果中(尽pipe是例外),但是实际的列文本(也是“HEADER 0”)缺失。

我想采取这样的方法,因为行数可以在100,000的数量,我想刷新数据到磁盘上的必要。

在JXLS中甚至有可能做这样的事情吗? 如果是这样,有没有办法改变模板,而不必编写任何知道数据的Java代码?

这里是代码:

public class JxlsTest { @Test public void sxssfDynamicColumns() throws Exception { List<Map<String, Object>> lotsOfStuff = createLotsOfStuff(); Context context = new PoiContext(); context.putVar("lotsOStuff", lotsOfStuff); context.putVar("columns", new Columns()); try (InputStream in = getClass().getClassLoader().getResourceAsStream("stuff_sxssf_template.xlsx")) { try (OutputStream os = new FileOutputStream("stuff_sxssf_out.xlsx")) { Workbook workbook = WorkbookFactory.create(in); PoiTransformer transformer = PoiTransformer.createSxssfTransformer(workbook, 5, false); AreaBuilder areaBuilder = new XlsCommentAreaBuilder(transformer); List<Area> xlsAreaList = areaBuilder.build(); Area xlsArea = xlsAreaList.get(0); xlsArea.applyAt(new CellRef("Result!A1"), context); SXSSFWorkbook workbook2 = (SXSSFWorkbook) transformer.getWorkbook(); workbook2.write(os); } } } private List<Map<String, Object>> createLotsOfStuff() { Map<String, Object> stuff1 = new LinkedHashMap<>(); Map<String, Object> stuff2 = new LinkedHashMap<>(); stuff1.put("header0", "stuff_1_value0"); stuff1.put("header1_dynamic", "stuff_1_value1"); stuff1.put("header2_dynamic", "stuff_1_value2"); stuff1.put("header3_dynamic", "stuff_1_value3"); stuff2.put("header0", "stuff_2_value0"); stuff2.put("header1_dynamic", "stuff_2_value1"); stuff2.put("header2_dynamic", "stuff_2_value2"); stuff2.put("header3_dynamic", "stuff_2_value3"); return Arrays.asList(stuff1, stuff2); } 

}

和支持“列”实用程序:

 public class Columns { public Collection<String> keyOf(List<Map<String, Object>> row) { return row.get(0).keySet().stream().filter(k -> k.endsWith("_dynamic")).collect(Collectors.toList()); } public Collection<Object> valueOf(Map<String, Object> row) { return row.entrySet().stream() .filter(entry -> entry.getKey() != null && entry.getKey().endsWith("_dynamic")) .map(Entry::getValue) .collect(Collectors.toList()); } 

}

和模板: 在这里输入图像说明

有足够的SXSSF窗口输出(注意HEADER 0出现):

在这里输入图像说明

输出的SXSSF窗口不足(注意HEADER 0不出现):

在这里输入图像说明

错误的SXXF窗口不足:

 18:33:20.653 [main] DEBUG org.jxls.area.XlsArea - Applying XlsArea at Result!A1 18:33:20.693 [main] ERROR org.jxls.area.XlsArea - Failed to transform Template!B1 into Result!B1 java.lang.IllegalArgumentException: Attempting to write a row[0] in the range [0,0] that is already written to disk. at org.apache.poi.xssf.streaming.SXSSFSheet.createRow(SXSSFSheet.java:115) ~[poi-ooxml-3.12.jar:3.12] at org.jxls.transform.poi.PoiTransformer.transform(PoiTransformer.java:112) ~[jxls-poi-1.0.8.jar:na] at org.jxls.area.XlsArea.transformTopStaticArea(XlsArea.java:232) [jxls-2.2.9.jar:na] at org.jxls.area.XlsArea.applyAt(XlsArea.java:134) [jxls-2.2.9.jar:na] 

更新我发现,如果我删除dynamic标题(请参阅截图中B4单元格中的模板),exception不会引发,一切正常。 因此,行相关的模板正在被评估,然后JXLS回来评估dynamic头模板。 有没有办法让JXLS先评估头文件?