如何使用Java POI从工作簿中删除所有公式

时间:2017-09-22 13:49:00

标签: java apache-poi array-formulas

几年前在这里问了同样的问题: how to remove all formulas from an excel sheet by java POI api?

然而,当时没有得到答案对我有用。 我有一个带有几个大表的工作簿,并希望循环所有单元格以用字符串替换单元格内容。问题是,许多单元格包含我必须先摆脱的公式。 public lineVistaChartOptions:any = { responsive: true, annotation:{ drawTime: 'afterDatasetsDraw', // (default) events: ['click'], dblClickSpeed: 350, // ms (default) annotations: { type: 'line', drawTime: 'afterDatasetsDraw', id: 'a-line-1', mode: 'horizontal', // ID of the scale to bind onto scaleID: 'y-axis-0', value: 50, endValue: 100, borderColor: 'red', borderWidth: 2, borderDash: [2, 2], borderDashOffset: 1, label: { backgroundColor: 'rgba(0,0,0,0.8)', fontFamily: "sans-serif", fontSize: 12, fontStyle: "bold", fontColor: "#fff", xPadding: 0, yPadding: 0, cornerRadius: 6, position: "center", xAdjust: 0, yAdjust: 0, enabled: true, content: "Test label" } } } cell.setCellFormula(null)(也不是cell.setCellType(CellType.STRING))都不令人满意,因为删除数组公式的基础过程需要很长时间,并使整个作业太慢。

以下工作但留下了损坏的Excel工作簿,只能在第一次修复步骤时打开: BLANK Method m = XSSFCell.class.getDeclaredMethod("setBlank"); m.setAccessible(true); 是否有任何其他快速和清洁的方法可以将某些单元格设置为空白,无论是否有任何公式?

2 个答案:

答案 0 :(得分:1)

出现损坏的工作簿的原因是/xl/calcChain.xml中存储了一个计算链。删除公式的常规慢速方法将更新此计算链。但是,正如您已经发现的那样,它们也试图仅用于删除单个公式,而不是全部。所以他们必须小心地删除部分数组公式,这会使它们变慢。

但是如果真的所有公式都要删除,那么这种谨慎是不必要的,然后只需删除整个/xl/calcChain.xml

示例:

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

import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;

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

import org.apache.poi.POIXMLDocumentPart;
import java.lang.reflect.Method;

class ExcelRemoveFormulasAndCalcChain {

 private static void removeCalcChain(XSSFWorkbook workbook) throws Exception {
  CalculationChain calcchain = workbook.getCalculationChain();
  Method removeRelation = POIXMLDocumentPart.class.getDeclaredMethod("removeRelation", POIXMLDocumentPart.class); 
  removeRelation.setAccessible(true); 
  removeRelation.invoke(workbook, calcchain);
 }

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

  XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("Test.xlsx"));

  for (Sheet sheet : workbook) {
   for (Row row : sheet) {
    for (Cell cell : row) {
     XSSFCell xssfcell = (XSSFCell)cell;
     if (xssfcell.getCTCell().isSetF() && xssfcell.getCTCell().getF().getT() != STCellFormulaType.DATA_TABLE) {
      xssfcell.getCTCell().unsetF();
     }
    }
   }
  }

  removeCalcChain(workbook);

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

 }
}

这应该删除所有公式,让所有单元格只包含值和样式。

答案 1 :(得分:0)

我想我能够找到如何删除某些单元格范围内的公式。 我注意到,如果我删除带有链接的工作表第一个公式,它会被快速删除。 如果我交换删除公式和删除工作表,则需要很多时间。 因此,如果我们创建一个工作表,使用指向它的链接重写所有公式,然后删除工作表,公式将被快速删除(设置带有不存在工作表链接的公式不起作用)。 15k+ 行需要几秒钟。这是实验:

    File fReport = new File(".xlsx");
    XSSFWorkbook book = new XSSFWorkbook(new FileInputStream(fReport));
    XSSFSheet sheet = book.getSheet("");

    XSSFSheet dummy = book.createSheet("dummy");

    int lastRow = sheet.getLastRowNum();
    for (int i = 8; i <= lastRow; i++) {
        XSSFRow rowToClean = sheet.getRow(i);
        XSSFCell cell = rowToClean.getCell(2);
        System.out.println(i);
        if (cell != null) {
            cell.setCellFormula("'dummy'!A1");
        }
    }
    book.removeSheetAt(book.getSheetIndex(dummy));
    
    for (int i = 8; i <= lastRow; i++) {
        XSSFRow rowToClean = sheet.getRow(i);
        XSSFCell cell = rowToClean.getCell(2);
        System.out.println(i);
        if (cell != null) {
            cell.removeFormula();
        }
    }

    book.write(new FileOutputStream(fReport));
    book.close();