使用Apache POI 3.7多次写入xlsx文档时出现异常

22

使用Apache POI尝试编写.xlsx文件时,我遇到了以下异常:org.apache.xmlbeans.impl.values.XmlValueDisconnectedException

看起来问题出在第二次使用write()方法。 当使用HSSFWorkbook时不会出现此问题。

这是代码:

public class SomeClass{

XSSFWorkbook workbook;

public SomeClass() throws IOException{
    File excelFile = new File("workbook.xlsx");

    InputStream inp = new FileInputStream(excelFile);
    workbook = new XSSFWorkbook(inp);
    inp.close();
}

void method(int i) throws InvalidFormatException, IOException {

    XSSFSheet sheet = workbook.getSheetAt(0);
    XSSFRow row = sheet.getRow(i);
    if (row == null) {
        row = sheet.createRow(i);
    }
    XSSFCell cell = row.getCell(i);
    if (cell == null)
        cell = row.createCell(i);
    cell.setCellType(Cell.CELL_TYPE_STRING);
    cell.setCellValue("a test");

    // Write the output to a file
    FileOutputStream fileOut = new FileOutputStream("workbook.xlsx");
    workbook.write(fileOut);
    fileOut.close();

}

public static void main(String[] args) throws Exception {
    SomeClass sc = new SomeClass();

    sc.method(1);
    sc.method(2);
}
}
7个回答

13

今天我也遇到了同样的问题。我注意到很多人在许多不同的论坛上问同样的问题,但我没有在任何地方看到答案。所以,这就是我想出来的解决方法。它远非理想(我可以想到至少两种情况下这可能不是一个好主意),并且可能不适合每个需求,但它能够工作!

在该工作簿对象作为属性的类中的每次保存操作之后,我重新加载了从我刚刚保存它的文件中的工作簿。

使用您上面的代码示例,我会修改该方法如下:

void method(int i) throws InvalidFormatException, IOException {
    ...

    // Write the output to a file
    FileOutputStream fileOut = new FileOutputStream("workbook.xlsx");
    workbook.write(fileOut);
    fileOut.close();

    // Reload the workbook, workaround for bug 49940
    // https://issues.apache.org/bugzilla/show_bug.cgi?id=49940
    workbook = new XSSFWorkbook(new FileInputStream("workbook.xlsx"));
}

我在我的代码中测试了这个解决方法,它很好地解决了问题。只需确保从保存的同一文件中读取回来,而不是以前或不同版本的文件。


1
Scott,感谢你的解决方法。我自己也发了一篇关于同样问题的帖子,并链接到了你的解决方法。虽然如你所说,这可能不是最有效的方法,但在Apache-POI团队决定修复此漏洞之前,这是一个很好的解决办法。 - Matthew Lancaster
感谢你提供的解决方法... 我添加了 new File("workbook.xlsx").delete();在末尾进行清理... - Fortega

10

1
更好的情况是如果有善良的人有时间来解决那个 bug :) - Gagravarr

3
我发现了一个解决方案,而且我已经找了一段时间。确保您不要使用用于打开FileOutputStream保存Workbook的文件来打开Workbook,而是使用FileInputStream打开Workbook。像这样做可以完美地工作。
        File inputFile = new File("Your-Path");
        this.inputStream = new FileInputStream(inputFile);
        this.opc = OPCPackage.open(this.inputStream);
        this.workbook = WorkbookFactory.create(opc);

...

        this.outputStream = new FileOutputStream(inputFile);
        this.workbook.write(this,outputStream);

不要忘记关闭每个已打开的流和OPCPackage

0

我在使用apache poi 3.10时也遇到了同样的问题。 但是在添加最新的apache poi jar文件之后,它对我起作用了。 请尝试更新jar文件到最新版本。


0

只有在尝试为 .xlsx 文件写入超过一次时才会出现此问题。我遇到了同样的问题,并通过以下方式解决:

  1. 之前我写了两次
  2. 现在删除了第一个写入调用
  3. 将相同的工作簿实例传递给方法并设置新单元格的值
  4. 最后通过写入几列和单元格对工作簿进行了一些更改
  5. 然后使用文件输出流进行了写入。

它正在工作


0

我也曾经遇到过同样的问题。后来,我尝试了另一种方法,问题得以解决。
在这种情况下,我们可以将代码移动到:

FileOutputStream fileOut = new FileOutputStream("workbook.xlsx");
workbook.write(fileOut);
fileOut.close();

在方法外部(out of the method)定义int i,然后在主方法中我们可以使用:

 sc.method(1); 
 sc.method(2); 
 FileOutputStream fileOut = new FileOutputStream("workbook.xlsx");
 workbook.write(fileOut);
 fileOut.close();

然后,workbook.write 只使用一次。此外,数据可以被多次修改。


-1

这似乎确实是XSSFSheet.createRow(int index)中的一个bug。只要这个bug没有修复,使用这个类作为解决方法就应该可以解决问题:

import java.util.Iterator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

public class PoiHacks
{
    // Fix of XSSFSheet.createRow(int index)
    public static Row createRow(Sheet sheet, int index) {
        Row row = sheet.getRow(index);
        if(row==null) return sheet.createRow(index);

        Iterator it = row.iterator();
        while(it.hasNext()) {
            it.next();
            it.remove();
        }
        return row;
    }
}

使用:

PoiHacks.createRow(sheet, 0);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接