【问题标题】:How to I get rid of “Save changes?” prompt on xlsx-files created with Apache POI XSSF如何摆脱“保存更改”?提示使用 Apache POI XSSF 创建的 xlsx 文件
【发布时间】:2016-12-13 12:20:29
【问题描述】:

我正在创建一个新的 .xlsx 文件,当我第一次打开它并关闭它时,就会出现这个烦人的弹出窗口。这个项目应该创建一个 Excel 文件,看起来就像我的同事手工做的那样,我在下面发布的 xml 文件来自他的一个文件。我保存文件的代码工作正常:

private File save() throws IOException {
    Date now = new Date();
    String userHome = System.getProperty("user.home");
    for (int fCounter = -1;; fCounter++) {
        Path path = Paths.get(MessageFormat.format(PATH_FMT, userHome, now, fCounter));
        try (OutputStream out = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW)) {
            this.workBook.write(out);
            this.workBook.close();
            return path.toFile();
        } catch (FileAlreadyExistsException incrCounterAndRetry) {
        }
    }
}

这里有一个关于我如何创建数据透视表的示例(也可以正常工作):

private void createPivotSid(XSSFSheet sheet) {
    XSSFSheet data = workBook.getSheet("SID Table");

    CellReference cr = new CellReference("A1");
    CellReference c1 = new CellReference(0, 0);
    CellReference c2 = new CellReference(data.getPhysicalNumberOfRows() - 1, data.getRow(0).getLastCellNum() - 1);

    AreaReference ar = new AreaReference(c1, c2);
    XSSFPivotTable pivotTable = sheet.createPivotTable(ar, cr, data);

    pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(5).setAxis(STAxis.AXIS_COL);
    pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(5).addNewItems();
    pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(5).getItems().addNewItem()
            .setT(STItemType.DEFAULT);

    pivotTable.getCTPivotTableDefinition().addNewColFields().addNewField().setX(5);

    pivotTable.addRowLabel(11);
    pivotTable.addRowLabel(12);
    pivotTable.addRowLabel(2);
    pivotTable.addColumnLabel(DataConsolidateFunction.COUNT, 1);
}

这一切都很好,但我得到了这个烦人的弹出窗口。所以我用谷歌搜索了很多,找到了this question on SO 并尝试了他们的建议。简单地评估所有公式的答案不起作用(这里没有公式)。所以我尝试了建议在打开之前编辑 xml-File 的答案。在这里,我在创建/设置定义的名称时遇到了问题(不确定这是什么,从示例 xml 复制)。我的代码是:

private void setWorkbookXmlContent() {
    workBook.getCTWorkbook().addNewFileVersion();
    workBook.getCTWorkbook().getFileVersion().setAppName("xl");
    workBook.getCTWorkbook().getFileVersion().setLastEdited("5");
    workBook.getCTWorkbook().getFileVersion().setLowestEdited("5");
    workBook.getCTWorkbook().getFileVersion().setRupBuild("9303");

    workBook.getCTWorkbook().getWorkbookPr().unsetDate1904();
    workBook.getCTWorkbook().getWorkbookPr().setDefaultThemeVersion(124226);

    workBook.getCTWorkbook().getBookViews().getWorkbookViewArray(0).setXWindow(480);
    workBook.getCTWorkbook().getBookViews().getWorkbookViewArray(0).setYWindow(105);
    workBook.getCTWorkbook().getBookViews().getWorkbookViewArray(0).setWindowWidth(27795);
    workBook.getCTWorkbook().getBookViews().getWorkbookViewArray(0).setWindowHeight(14310);
    workBook.getCTWorkbook().getBookViews().getWorkbookViewArray(0).unsetActiveTab();

    workBook.getCTWorkbook().addNewDefinedNames().addNewDefinedName().setName("_xlnm._FilterDatabase");
    workBook.getCTWorkbook().addNewDefinedNames().addNewDefinedName().setLocalSheetId(3);
    workBook.getCTWorkbook().addNewDefinedNames().addNewDefinedName().setHidden(false);
    workBook.getCTWorkbook().addNewDefinedNames().addNewDefinedName().setStringValue("SID Q3 2016'!$A$1:$M$81");

    workBook.getCTWorkbook().addNewCalcPr().setCalcId(145621);

}

我试图实现的 xml 文件如下所示(来自我同事的 Excel 文件):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="9303"/>
<workbookPr defaultThemeVersion="124226"/>
<bookViews><workbookView xWindow="480" yWindow="45" windowWidth="27795" windowHeight="14370"/></bookViews>
<sheets><sheet name="Overview SID" sheetId="3" r:id="rId1"/><sheet name="Overview Exchange" sheetId="5" r:id="rId2"/><sheet name="Overview Total Cost" sheetId="6" r:id="rId3"/><sheet name="SID Q3 2016" sheetId="1" r:id="rId4"/><sheet name="Exchange Q3 2016" sheetId="2" r:id="rId5"/><sheet name="Total Cost Q3 2016" sheetId="4" r:id="rId6"/></sheets>
<definedNames><definedName name="_xlnm._FilterDatabase" localSheetId="3" hidden="1">'SID Q3 2016'!$A$1:$M$81</definedName></definedNames>
<calcPr calcId="145621"/>
<pivotCaches><pivotCache cacheId="8" r:id="rId7"/><pivotCache cacheId="15" r:id="rId8"/><pivotCache cacheId="21" r:id="rId9"/></pivotCaches>
</workbook>

但我实际上得到的是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="9303"/><workbookPr defaultThemeVersion="124226"/>
<bookViews><workbookView xWindow="480" yWindow="105" windowWidth="27795" windowHeight="14310"/></bookViews>
<sheets><sheet name="SID Table" r:id="rId3" sheetId="1"/><sheet name="Exchange Table" r:id="rId4" sheetId="2"/><sheet name="Total Cost Table" r:id="rId5" sheetId="3"/><sheet name="Overview SID" r:id="rId6" sheetId="4"/><sheet name="Overview Exchange" r:id="rId8" sheetId="5"/><sheet name="Overview Total Cost" r:id="rId10" sheetId="6"/></sheets>
<definedNames><definedName localSheetId="3"/></definedNames>
<definedNames><definedName hidden="1"/></definedNames>
<definedNames><definedName>SID Q3 2016'!$A$1:$M$81</definedName></definedNames>
<definedNames><definedName localSheetId="3"/></definedNames>
<calcPr calcId="145621"/>
<pivotCaches><pivotCache cacheId="2" r:id="rId7"/><pivotCache cacheId="3" r:id="rId9"/><pivotCache cacheId="4" r:id="rId11"/></pivotCaches>
</workbook>

也许有人可以解决我的问题,或者我可以帮助进行 xml 编辑。任何帮助表示赞赏。

更新

我找到了一种摆脱弹出窗口的方法 (pivotTable.getPivotCacheDefinition().getCTPivotCacheDefinition().setRefreshOnLoad(false);),但现在我需要在保存之前“评估”所有数据透视表。或者是否可以保存工作簿,然后在新工作簿中打开文件(这应该刷新数据透视表?)然后保存?

【问题讨论】:

  • 定义的名称没有名称属性......所以这看起来很奇怪。我会先尝试使用完整的模式。你没有使用 OSGi 吗?
  • 疯狂猜测。添加新的数据透视对象不会更新内部缓存的单元格值。一旦您打开 Excel 就会认为这是一个“脏”文件并计算公式和对象。缓存的值存储到单元格中。公式单元格在 xmlx 文件中具有最后计算的值和公式道具。 Pivot 的行为可能类似。
  • definedName name="_xlnm._FilterDatabase"这是由excel生成的。
  • “这个烦人的弹出窗口出现了”。这并不烦人。 Apache poi 无法正确创建数据透视表 - 意味着包含正确的数据透视缓存。因此,实际上 Excel 将创建数据透视表,同时从 apache poi 中未完成的部分内容打开 *.xlsx 文件。所以 Excel 进行了更改,因此 Excel 必须 至少要求保存这些更改。
  • @AxelRichter 有没有办法以编程方式创建数据透视表,这样这个弹出窗口就不会出现?

标签: java xml excel apache-poi


【解决方案1】:

如果您对宏没问题,您可以创建一个外部帮助程序 xlsm 文件和 VBA 宏,以便在 Excel 应用程序中打开后运行。如果要自动执行此操作,请使用 Java 的 shell-execute。用户确实需要完整的 Excel 安装。

Private Sub Auto_open()
  // you could foreach loop pivottables array
  // but this example uses a predefined instance names
  Dim wb as workbook
  Dim ws as worksheet

  Set wb = Application.Workbooks.Open("c:\data\mypoifile.xlsx", 3, False, 5, "", "", True, xlWindows, "", False, False, 0, False, True, xlNormalLoad)

  set ws = wb.Worksheets("data1")
  ws.PivotTables("PivotTable1").PivotCache.Refresh
  ws.PivotTables("PivotTable2").PivotCache.Refresh
  set ws = wb.Worksheets("data2")
  ws.PivotTables("PivotTable3").PivotCache.Refresh
  ws.PivotTables("PivotTable4").PivotCache.Refresh

  wb.Close(true) // save+close poi file
  ActiveWorkbook.close(false)
End Sub

您可能需要使用这种 hack 的原因是 POI 只是一个“简单”的 Excel 文件格式处理程序,无需安装 Excel 即可工作。 POI 对真正的 Excel 运行时 UI 引擎功能一无所知,许多 xls 文件格式的事情只发生在 UI 引擎级别。

【讨论】:

  • 在我最后的评论中,我并不是说我想要一个 VBA 宏。我的意思是有纯java代码来完成任务。但感谢您的努力
猜你喜欢
  • 1970-01-01
  • 2021-02-10
  • 2011-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多