Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 带JXLS 2的SXSSF变压器_Java_Excel_Apache Poi_Jxls - Fatal编程技术网

Java 带JXLS 2的SXSSF变压器

Java 带JXLS 2的SXSSF变压器,java,excel,apache-poi,jxls,Java,Excel,Apache Poi,Jxls,我想将SXSSF变压器与JXLS一起使用。我试图以这样一种方式编写模板,即不会出现“试图在已写入磁盘的范围内写入行”异常。该模板捕获已知列(例如,“HEADER 0”)和未知列(以“\u dynamic”结尾的列)。动态列的数量因运行而异 如果我将SXSSF窗口配置为大于行数,则没有问题。如果我将窗口设置为小于行数,则会出现“尝试写入行…”异常。但是,在这两种情况下都会创建工作簿。如果窗口大小足够大,结果中将包含已知列(“标题0”)。窗口大小不足时,结果中包含已知列值(尽管存在异常),但缺少实际

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

如果我将SXSSF窗口配置为大于行数,则没有问题。如果我将窗口设置为小于行数,则会出现“尝试写入行…”异常。但是,在这两种情况下都会创建工作簿。如果窗口大小足够大,结果中将包含已知列(“标题0”)。窗口大小不足时,结果中包含已知列值(尽管存在异常),但缺少实际列文本(同样是“标题0”)

我想采用这样的方法,因为行的数量可能会达到100000,我想根据需要将数据刷新到磁盘

在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);
}
更新
我发现,如果删除动态标题(请参见屏幕截图中B4单元格中的模板),则不会引发异常,并且一切正常。因此,将首先评估与行相关的模板,然后JXLS将返回以评估动态头模板。有没有办法让JXLS首先评估标头模板?

问题是JXLS分两个阶段处理静态单元格

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

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

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

现在有了Jxls
master
分支,如果使用流式转换器,该分支应通过以不同方式处理静态单元来解决问题。另见相关文件


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

如果您发现需要触摸已刷新到磁盘的行,为什么不增加该修复程序?我尝试构建模板,使Jxls可以线性写入行,而不必重新访问以前写入的行。
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());
}
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]