首页 > 解决方案 > 使用 apache-poi 更新 excel 文件时出现 POIXMLException

问题描述

当我尝试覆盖现有的 excel 文件时,我收到以下错误消息:

Exception in thread "main" org.apache.poi.ooxml.POIXMLException: OOXML file structure broken/invalid - no core document found!
at org.apache.poi.ooxml.POIXMLDocumentPart.getPartFromOPCPackage(POIXMLDocumentPart.java:783)
at org.apache.poi.ooxml.POIXMLDocumentPart.<init>(POIXMLDocumentPart.java:175)
at org.apache.poi.ooxml.POIXMLDocumentPart.<init>(POIXMLDocumentPart.java:165)
at org.apache.poi.ooxml.POIXMLDocument.<init>(POIXMLDocument.java:61)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:282)
at Test.main(Test.java:16)

顺便说一句,如果我尝试编写一个新的 excel 文件没有问题。所以它工作正常,但我无法更新现有文件。我究竟做错了什么?有我的代码:

public static void main(String[] args) throws InvalidFormatException, IOException {
    File file = new File("C:/Users/yavuz/IdeaProjects/inspection/src/main/java/inspection.xlsx");
    OPCPackage pkg = OPCPackage.open(file);
    FileOutputStream outputStream = new FileOutputStream(file);
    XSSFWorkbook wb = new XSSFWorkbook(pkg);

    int finding = 445;

    DataFormatter formatter = new DataFormatter();
    for(Sheet sheet : wb) {
        for(Row row : sheet){
            if(row.getCell(0)!=null && !formatter.formatCellValue(row.getCell(0)).equals("")){
                Cell cell = row.getCell(0);
                String text = formatter.formatCellValue(cell);
                if('0'<=text.charAt(0) && text.charAt(0)<='9') {
                    int id = Integer.parseInt(text);
                    if (id == finding) {
                        System.out.println(sheet.getSheetName());
                        System.out.println(sheet.getRow(row.getRowNum()).getCell(1));
                        Cell cellCurrent = row.getCell(2);
                        if (cellCurrent == null){
                            cellCurrent = row.createCell(2);
                        }
                        cellCurrent.setCellValue("X");

                        wb.write(outputStream);
                        outputStream.close();
                    }
                }
            }
        }
    }
}

标签: javaexceljakarta-eeapache-poiapache-commons

解决方案


您的代码中有多个问题。

如果您从 a创建一个OPCPackageor a ,只要or没有关闭,您就不能拥有同一个文件。这是因为直接从该文件中获取其数据的或打开的。因此内存占用量较低,因为并非所有数据都在随机存取内存中。但是文件被锁定了。XSSFWorkbookFileFileOutputStreamOPCPackageXSSFWorkbookOPCPackageXSSFWorkbookFile

如果需要从 a 读取File并写入相同File的 ,那么使用FileInputStreamfor reading 和FileOutputStreamfor writing 是必要的。

并且您无法在每次更改后写出工作簿。在Workbook.write工作簿还没有准备好从中获取数据之后。所以工作簿需要在所有更改完成后写出一次。

并且整个创建OPCPackage是没有必要的。更好的方法是直接从FileInputStream.

XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(file));

更好的是使用WorkbookFactory.create它,因为它能够创建HSSFXSSF Workbook依赖于给定的文件。

Workbook wb = WorkbookFactory.create(new FileInputStream(file));

以下代码经过测试并使用apache poi 4.1.2.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.poi.ss.usermodel.*;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

class ExcelFromOPC {

  public static void main(String[] args) throws Exception {
    File file = new File("./inspection.xlsx");

    //OPCPackage pkg = OPCPackage.open(file);
    OPCPackage pkg = OPCPackage.open(new FileInputStream(file));
    XSSFWorkbook wb = new XSSFWorkbook(pkg);
    
    //XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(file));
    //Workbook wb = WorkbookFactory.create(new FileInputStream(file));

    //wb -> sheets -> rows -> cols
    int finding = 445;

    DataFormatter formatter = new DataFormatter();
    boolean write = false;
    for(Sheet sheet : wb) {
      for(Row row : sheet) {
        if(row.getCell(0)!=null && !formatter.formatCellValue(row.getCell(0)).equals("")) {
          Cell cell = row.getCell(0);
          String text = formatter.formatCellValue(cell);
          if('0'<=text.charAt(0) && text.charAt(0)<='9') {
            int id = Integer.parseInt(text);
            if (id == finding) {
              System.out.println(sheet.getSheetName());
              System.out.println(sheet.getRow(row.getRowNum()).getCell(1));
              Cell cellCurrent = row.getCell(2);
              if (cellCurrent == null) {
                cellCurrent = row.createCell(2);
              }
              cellCurrent.setCellValue("X");
              write = true;
            }
          }
        }
      }
    }

    if (write) {
        System.out.println("writing");
        FileOutputStream outputStream = new FileOutputStream(file);
        wb.write(outputStream);
        outputStream.close();
        wb.close();
    }
  }

}

推荐阅读