Java.io.EOFException:使用Apache POI时ZLIB输入流意外结束

8
我正在尝试使用Apache POI创建Excel数据透视表。
目前,当我尝试在工作簿中写入数据workbook.write(fileOut);时,会出现异常。

org.apache.poi.ooxml.POIXMLException: java.io.EOFException: 意外的ZLIB输入流结束

以下是该类的代码:

public class PivotTable {



public static void createPivotTable(String pathToWorkbook, String sheetName) throws IOException {

    Workbook workbook = new XSSFWorkbook(pathToWorkbook);

    XSSFSheet sheet = (XSSFSheet) workbook.getSheet(sheetName);

    int firstRowInd = sheet.getFirstRowNum();
    int lastRowInd = sheet.getLastRowNum();
    int firstCellInd = sheet.getRow(0).getFirstCellNum();
    int lastCellInd = sheet.getRow(0).getLastCellNum() - 1;

    //Specifying top left ant the bottom right of the table data
    CellReference topLeft = new CellReference(firstRowInd, firstCellInd);
    CellReference botRight = new CellReference(lastRowInd, lastCellInd);

    //The area of data in table
    AreaReference aref = new AreaReference(topLeft, botRight, SpreadsheetVersion.EXCEL2007);

    //Position of the pivot table
    CellReference pos = new CellReference(firstRowInd + 4, lastCellInd + 1);

    //Creating the pivot table
    XSSFPivotTable pivotTable = sheet.createPivotTable(aref, pos);


    pivotTable.addRowLabel(0);
    pivotTable.addRowLabel(2);
    pivotTable.addColLabel(3);

    FileOutputStream fileOut = new FileOutputStream(pathToWorkbook);
    workbook.write(fileOut);
    fileOut.close();


}

以下是异常的堆栈跟踪:

Exception in thread "main" org.apache.poi.ooxml.POIXMLException: java.io.EOFException: Unexpected end of ZLIB input stream
    at org.apache.poi.ooxml.POIXMLDocument.getProperties(POIXMLDocument.java:147)
    at org.apache.poi.ooxml.POIXMLDocument.write(POIXMLDocument.java:240)
    at PivotTable.createPivotTable(PivotTable.java:50)
    at Main.main(Main.java:14)
Caused by: java.io.EOFException: Unexpected end of ZLIB input stream
    at java.util.zip.InflaterInputStream.fill(InflaterInputStream.java:240)
    at org.apache.commons.compress.archivers.zip.InflaterInputStreamWithStatistics.fill(
InflaterInputStreamWithStatistics.java:52)
    at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:158)
    at org.apache.commons.compress.archivers.zip.InflaterInputStreamWithStatistics.read(
InflaterInputStreamWithStatistics.java:67)
    at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:122)
    at org.apache.commons.compress.archivers.zip.InflaterInputStreamWithStatistics.read(
InflaterInputStreamWithStatistics.java:58)
    at java.io.FilterInputStream.read(FilterInputStream.java:83)
    at org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream.read(ZipArchiveThresholdInputStream.java:69)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(XMLEntityManager.java:2890)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:674)
    at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:148)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:805)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
    at org.apache.xmlbeans.impl.store.Locale$SaxLoader.load(Locale.java:3414)
    at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1272)
    at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1259)
    at org.apache.xmlbeans.impl.schema.SchemaTypeLoaderBase.parse(SchemaTypeLoaderBase.java:345)
    at org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument$Factory.parse(Unknown Source)
    at org.apache.poi.ooxml.POIXMLProperties.(POIXMLProperties.java:81)
    at org.apache.poi.ooxml.POIXMLDocument.getProperties(POIXMLDocument.java:145)
    ... 3 more
3个回答

16

我遇到了同样的问题,我通过更改这一行来解决它:

Workbook workbook = new XSSFWorkbook(pathToWorkbook);

至:

Workbook workbook = new XSSFWorkbook(new FileInputStream(pathToWorkbook));

希望这有所帮助! :)


这个答案的缺点是,Apache POI文档建议使用File而不是FileInputStream,因为FileInputStream更加占用内存。但是在观察到的行为中,这似乎是Apache POI中的一个缺陷,防止在修改现有文档时使用File。 - denver

9

很有把握问题出在您覆盖了文件上。尝试将其保存到不同的路径。如果您仍想覆盖该文件,请先保存为其他文件名,删除原始文件,然后将您编写的文件重命名为原来的文件名:

try (FileOutputStream fileOut = new FileOutputStream(pathToWorkbook + ".new")) {
    workbook.write(fileOut);
}
Files.delete(Paths.get(pathToWorkbook));
Files.move(Paths.get(pathToWorkbook + ".new"), Paths.get(pathToWorkbook));

我尝试了一下。新文件包含所有工作表已经被创建并且可以使用,但是当我尝试使用Files.move()时,出现了"Exception in thread "main" java.nio.file.FileAlreadyExistsException: samples\Sample Tables New.xlsx -> samples\Sample Tables.xlsx"的错误提示。 - Андрей Суручану
为了解决这个问题,我只需使用以下代码重命名文件:new File(pathToWorkbook).renameTo(new File("tmpName.xlsx")); Files.delete(Paths.get("tmpName.xlsx")); - Андрей Суручану
Files.move不会默默地覆盖现有文件,你必须明确要求它这样做:Files.move(from, to, StandardCopyOption.REPLACE_EXISTING);。不要切换回过时的API,因为它往往会导致不安全的代码(java.io.)。 - undefined
请注意,您没有按照我的示例代码的方式进行操作,首先要“删除”已有内容。要么您没有复制该部分,要么复制失败了(renameTo也会失败),或者其他进程正在同时写入该文件,这是一个随机事件 - 在这种情况下,您需要一种锁定系统来控制此过程,不能同时有两个进程尝试写入同一个文件并且最终结果是有意义的。 - undefined

2

似乎workbook.write()方法存在一个小bug。我找到了两个解决方法。 第一个是为FileOutputStream指定另一个(虚拟的)文件名。当workbook关闭时,两个文件都会被填充。 第二个解决方法更好,即为workbook.write()方法指定虚拟OutputStream:

OutputStream dummyOutputStream = new OutputStream() {
            @Override
            public void write(int b) throws IOException {

            }
        };
        workbook.write(dummyOutputStream);
        dummyOutputStream.close();
        workbook.close();

这似乎不是一个解决方案。使用虚拟文件流导致文件未被修改。因此,对文件的更改没有被写出。 - denver

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