延迟将值写入具有公式的Excel文件

时间:2019-04-27 16:16:11

标签: java excel excel-formula apache-poi apache-poi-4

用例:我有一个用excel实现的成本计算器。我必须在工作表的输入单元格中插入大量输入,并从同一工作表获取输出。我有3张excel表格,大小约为3MB。 Excel工作表为.xlsm格式。

使用的技术:Java 1.8和Apache POI 4.0.1

问题:将输入值写入大于3MB的excel文件的速度很快(大约12个输入大约需要10秒)。但是对excel文件执行的相同操作是<3MB太慢(仅一次输入就需要10秒)。

我似乎这里有人说要使用SXSSFWorkbook。我用它替换了XSSFWorkbook,但是它给了我Null Pointer Exception。另外,它用于大于100MB的大型Excel工作表,对吧?

用于编写值的代码:

    public void setData1(String filePath, String sheetName, int rowNum, int colNum, Object data) throws IOException {
        File file = new File(filePath); 
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            Messages.terminate(file.getName() + " file is missing.");
        }
        Workbook workbook = new XSSFWorkbook(fis);
        Sheet sheet = workbook.getSheet(sheetName);
        Row row = sheet.getRow(rowNum);
        Cell cell = row.getCell(colNum);
        if(data instanceof Integer) {
            cell.setCellValue((int)data);
        }
        else if (data instanceof String) {
            cell.setCellValue(String.valueOf((String) data));
        }
        else if(data instanceof Double) {
            if((double)data == Math.floor((double)data)) {
                cell.setCellValue((int)Math.floor((double)data));
            }
            else {
                cell.setCellValue((double)data);
            }
        }
        FileOutputStream fos = new FileOutputStream(new File(filePath));
        BaseFormulaEvaluator.evaluateAllFormulaCells(workbook);
        workbook.write(fos);
        workbook.close();
        fos.close();
        fis.close();
    }

1 个答案:

答案 0 :(得分:0)

以下代码仅打开工作簿一次,而不是针对输入的每个值重复打开和关闭工作簿:

public void setData1(Workbook workbook, FileOutputStream fos, String filePath, String sheetName, int rowNum, int colNum, Object data) throws IOException {
    Sheet sheet = workbook.getSheet(sheetName);
    Row row = sheet.getRow(rowNum);
    Cell cell = row.getCell(colNum);
    if(data instanceof Integer) {
        cell.setCellValue((int)data);
    }
    else if (data instanceof String) {
        cell.setCellValue(String.valueOf((String) data));
    }
    else if(data instanceof Double) {
        if((double)data == Math.floor((double)data)) {
            cell.setCellValue((int)Math.floor((double)data));
        }
        else {
            cell.setCellValue((double)data);
        }
    }
    BaseFormulaEvaluator.evaluateAllFormulaCells(workbook); //I don't have enough context here, but if it does not cause any logical problems, move this line to *
    workbook.write(fos);
}

public void callsSetData1() {
    object Data = new Object()
    File file = new File(filePath); 
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(file);
    } catch (FileNotFoundException e) {
        Messages.terminate(file.getName() + " file is missing.");
    }
    Workbook workbook = new XSSFWorkbook(fis);
    FileOutputStream fos = new FileOutputStream(new File(filePath));
    //*
    for(i = 0; i < 10; i++) {
        setData1(workbook, fos, "R:\andom\File\Path", "randomSheetName",0,0, data); //I'm assuming you are calling setData1() multiple times, as I do not have the code of the method that calls it, I've just used a for-loop for now
    }
    workbook.close();
    fos.close();
    fis.close();
}

我建议您还提供调用setData1的方法的代码。由于我没有这个,callsSetData1可能包含一些逻辑错误。

重点是,在调用setData1并将其作为参数传递的方法中,只应打开和关闭工作簿一次。这应该有助于延迟。

唯一的次要缺点是,如果您使用多种不同的方法调用setData1,则会有几行代码。