6

使用以下代码,不会保存对我的 Excel 电子表格所做的单元格值更改:

OPCPackage pkg = OPCPackage.open(inputFile);
XSSFWorkbook wb = new XSSFWorkbook(pkg);

ModifyWorkbook();

pkg.close();

以下是我写的解决方法,但我不明白为什么它是必要的。

OPCPackage pkg = OPCPackage.open(inputFile);
XSSFWorkbook wb = new XSSFWorkbook(pkg);

ModifyWorkbook();

File tmp = File.createTempFile("tempSpreadsheet", ".xlsx");
FileOutputStream newExcelFile = new FileOutputStream(tmp);
wb.write(newExcelFile);
newExcelFile.close();
tmp.deleteOnExit();
pkg.close();

该主题的 javadocs 和指南表明 .close() 方法应该保存并关闭。在关闭之前检查修改的单元格的值表明已进行更改,但仅 pkg.close() 方法不足以在关闭时将这些更改写入文件。

4

3 回答 3

2

调用OPCPackage.close()将关闭底层 OOXML 文件结构。它不会做的是导致 XSSF(或任何 X??F 格式)写出他们的更改。因此,您将写出一个未更改的文件....

如果您正在进行低级修改,您可以打开 OPCPackage,进行更改,然后调用 close 将它们写出来。如果您正在做高级别的事情,您打开 OPCPackage,使用 UserModel 代码进行更改,然后让 usermodel写出它的更改。这最后一步很重要。

您当前的代码有点像:

File f = new File("test.txt");
Sting s = readFileCompletely(f);
s = s.replaceAll("foo", "bar");
f.close();
// Why hasn't the file contents changed?

读取文件并修改高级对象是不够的,您还需要告诉高级对象写出更改。(出于性能原因,高级对象将事物缓存在内存中)

于 2013-04-19T21:33:45.210 回答
1

调用close(XSSF)工作簿将调用 javadoc 声明的 OPCP.close:

调用myWorkbook.close()应该将更改写入它打开的文件。

但是,当前版本(3.15)似乎在这样做时遇到了问题。我不知道原因本身,但我发现调用myWorkbook.write()不仅会将更改提交到输出流,还会在调用 close 后提交到当前实例。

因此,一个合理的解决方法可能是:

try (OutputStream bos = ByteStreams.nullOutputStream()){
    workbook.write(bos);
    workbook.close();
} catch (IOException e) {
    log.error("Could not write Output File", e);
}

这里使用Guavas ByteStreams完成。随意使用其他空输出流实现。

于 2017-04-06T14:47:17.173 回答
0

在最新版本的 POI 中,如果我们通过默认构造函数创建 org.apache.poi.xssf.usermodel.XSSFWorkbook 的对象,我们不需要手动执行此操作。读取它的默认构造方法

public XSSFWorkbook() {
        super(newPackage());
        onWorkbookCreate();
    }
protected static OPCPackage newPackage() {
        try {
            OPCPackage pkg = OPCPackage.create(new ByteArrayOutputStream());
            // Main part
            PackagePartName corePartName = PackagingURIHelper.createPartName(XSSFRelation.WORKBOOK.getDefaultFileName());
            // Create main part relationship
            pkg.addRelationship(corePartName, TargetMode.INTERNAL, PackageRelationshipTypes.CORE_DOCUMENT);
            // Create main document part
            pkg.createPart(corePartName, XSSFRelation.WORKBOOK.getContentType());

            pkg.getPackageProperties().setCreatorProperty(DOCUMENT_CREATOR);

            return pkg;
        } catch (Exception e){
            throw new POIXMLException(e);
        }
    }
于 2018-06-20T16:43:26.223 回答