gpt4 book ai didi

java - 带 JXLS 2 的 SXSSF 变压器

转载 作者:行者123 更新时间:2023-12-04 19:51:10 29 4
gpt4 key购买 nike

我想将 SXSSF 转换器与 JXLS 一起使用。我试图以这样一种方式编写我的模板,即我不会得到“试图在已经写入磁盘的范围内写入一行”异常。该模板捕获已知列(例如“HEADER 0”)和未知列(以“_dynamic”结尾的列)。动态列的数量可能因运行而异。

如果我将 SXSSF 窗口配置为大于行数,我没有问题。如果我将窗口设置为少于行数,则会出现“正在尝试写入一行...”异常。但是,在这两种情况下都会创建工作簿。如果窗口大小足够大,已知列(“HEADER 0”)将包含在结果中。如果窗口大小不合适,已知的列值会出现在结果中(尽管有异常(exception)),但实际的列文本(同样是“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);
}

和支持的“Columns”实用程序:

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());
}

和模板: enter image description here

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

enter image description here

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

enter image description here

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]

更新我发现如果我删除动态 header (请参阅屏幕截图中 B4 单元格中的模板),则不会引发异常并且一切正常。因此,首先评估与行相关的模板,然后 JXLS 返回评估动态 header 模板。有没有办法让 JXLS 先评估 header 模板?

最佳答案

问题在于 Jxls 分两个阶段处理静态单元格。

第一阶段发生在应用命令之前,它只处理顶部命令行之前的单元格。

第二阶段在处理完所有命令后触发,并尝试处理所有剩余的静态单元格。

第二阶段不适用于 SXSSF 工作簿,因为它无法更新位于命令处理期间写入的单元格之前的静态单元格。

现在有 a fix致力于 Jxls master 分支,如果使用流式转换器,它应该通过以不同方式处理静态单元格来解决问题。另见相关 Jxls issue #160 .

修复应该在即将发布的 Jxls 2.7.0 中发布。

关于java - 带 JXLS 2 的 SXSSF 变压器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36241753/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com