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

时间:2017-09-19 08:44:58

标签: java apache-poi xlsx xlsm

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

  

文件'FileName.xlsx'是一个无宏文件,但包含   启用宏的内容

代码的关键部分:

打开工作簿:

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 );
    }
}

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

1 个答案:

答案 0 :(得分:2)

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

以下代码通过从包中获取和删除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();

 }
}