Poi:从 xlsm 打开后将 excel 文件另存为 xlsx

Poi: Saving an excel file as xlsx after opening it from xlsm

我正在编写一个 java 程序,它打开一个用户定义的 excel 文件,用数据填充它,然后将它保存在用户指定的路径、文件名和扩展名下。应该可以,但不可能将输出声明为 xlsx,即使输入文件是 xlsm。如果我尝试使用下面的代码,打开文件会出现错误:

The file 'FileName.xlsx' is a macro-free file, but contains macro-enabled content

关键代码段:

打开工作簿:

try (Workbook workbook = WorkbookFactory.create( new FileInputStream( templateFile ) )) {
    // ...processing the file here, 
    // including a call of stripMacros, c.f. below
} catch ( IOException | EncryptedDocumentException | InvalidFormatException ex ) {
    throw new TemplateNotFoundException( "Template not found. Please check property templatePath: " + templateFile, ex );
}

正在将工作簿设置为正确的类型:

private Workbook stripMacros( final Workbook wb, final String outputFormat ) {
    Workbook workbook = wb;
    if ( "xlsx".equals( outputFormat ) && ( workbook.getClass() == XSSFWorkbook.class ) ) { 
        XSSFWorkbook wbx = (XSSFWorkbook) workbook;
        wbx.setWorkbookType( XSSFWorkbookType.valueOf( "XLSX" ) );
        return wbx;
    } else if ( "xlsm".equals( outputFormat ) && ( workbook.getClass() == XSSFWorkbook.class ) ) {
        XSSFWorkbook wbm = (XSSFWorkbook) workbook;
        wbm.setWorkbookType( XSSFWorkbookType.valueOf( "XLSM" ) );
        return wbm;
    } else {
        return wb;
    }
}

正在保存工作簿:

File outFile = new File( destinationPath, fileName + "." + outputFormat ); 
outFile.getParentFile().mkdirs();
if ( workbook != null ) {
    try {
        workbook.write( new FileOutputStream( outFile ) );
        workbook.close();
    } catch ( IOException ex ) {
        throw new FileInaccessibleException( "Workbook could not be saved. Please check if the workbook under " + destinationPath  + fileName + "." + outputFormat + " is not open in any program.", ex );
    }
}

我需要添加什么才能正确打开我的文件?我是否需要手动删除宏,如果需要,如何删除?

设置 WorkbookType 仅更改内容类型,但不会从 XLSM 文件内容中删除 VBA 项目。

以下代码通过从包中获取和删除 vbaProject.bin 部分来完成此操作。此外,它还会从包中获取并删除与已删除 vbaProject.bin 部分的关系。

在此之后,新的 XLSX 文件不再包含 VBA 代码。

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

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.PackageRelationship;

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

import java.util.regex.Pattern;

class ReadXSLMWriteXLSXWorkbook {

 public static void main(String[] args) throws Exception {

  XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("Workbook.xlsm"));

  OPCPackage opcpackage = workbook.getPackage();

  //get and remove the vbaProject.bin part from the package
  PackagePart vbapart = opcpackage.getPartsByName(Pattern.compile("/xl/vbaProject.bin")).get(0);
  opcpackage.removePart(vbapart);

  //get and remove the relationship to the removed vbaProject.bin part from the package
  PackagePart wbpart = workbook.getPackagePart();
  PackageRelationshipCollection wbrelcollection = wbpart.getRelationshipsByType("http://schemas.microsoft.com/office/2006/relationships/vbaProject");
  for (PackageRelationship relship : wbrelcollection) {
   wbpart.removeRelationship(relship.getId());
  }

  //set content type to XLSX
  workbook.setWorkbookType(XSSFWorkbookType.XLSX);

  Sheet sheet = workbook.getSheetAt(0);
  Row row = sheet.getRow(0);
  if (row == null) row = sheet.createRow(0);
  Cell cell = row.getCell(0);
  if (cell == null) cell = row.createCell(0);
  cell.setCellValue("changed");

  workbook.write(new FileOutputStream("Workbook.xlsx"));
  workbook.close();

 }
}