java - 使用 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();
}
}
}
}
}
}
解决方案
您的代码中有多个问题。
如果您从 a创建一个OPCPackage
or a ,只要or没有关闭,您就不能拥有同一个文件。这是因为直接从该文件中获取其数据的或打开的。因此内存占用量较低,因为并非所有数据都在随机存取内存中。但是文件被锁定了。XSSFWorkbook
File
FileOutputStream
OPCPackage
XSSFWorkbook
OPCPackage
XSSFWorkbook
File
如果需要从 a 读取File
并写入相同File
的 ,那么使用FileInputStream
for reading 和FileOutputStream
for writing 是必要的。
并且您无法在每次更改后写出工作簿。在Workbook.write
工作簿还没有准备好从中获取数据之后。所以工作簿需要在所有更改完成后写出一次。
并且整个创建OPCPackage
是没有必要的。更好的方法是直接从FileInputStream
.
XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(file));
更好的是使用WorkbookFactory.create
它,因为它能够创建HSSF
或XSSF
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();
}
}
}
推荐阅读
- shiny - 具有默认选定值的 ShinyTree
- python - 如何为图像/图标小部件设置动画
- javascript - 使用 jQuery 和 PHP 使用从 MySQL 数据库查询的 JSON 数据填充 HTML 选择字段
- javascript - 在春季上传多个文件,每个文件都有附加信息
- sql - 如何在 oracle 中拆分用逗号分隔的名称(偶数出现)?
- google-cloud-platform - gsutil rsync 是否会为 Google Cloud Storage Coldline 存储分区产生额外费用
- python - 阈值必须是数字且非NAN,打印numpy数组时,为什么numpy.nan在python3中未定义
- vb.net - 如何在 vb.net 的文本文件中输入附加数据?
- .net-core - .NET Core API 无法连接到 MS LocalDB
- django - Django从另一个表中的模型输出1个字段