NPOI保留EXCEL公式并赋值导出

使用NPOI操作EXCEL时,单元格内相关公式需要执行特定代码去保留,同时针对模板写入数据后导出的文件,需要通过代码执行,否则导出内容不会触发公式的计算

核心代码

 using (var file = new FileStream(strTemplate, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    // 直接读取模板的完整Workbook,包含所有样式、公式、格式
    xssfWorkbook = new XSSFWorkbook(file);
 }

/// <summary>
/// 核心赋值方法(保留模板格式和公式)
/// </summary>
/// <param name="dto">导出数据DTO</param>
/// <param name="sheet">目标工作表</param>
private void SetSheetCellValue(BIReportDto dto, XSSFSheet sheet, int dateVal) // 替换YourDtoType为实际DTO类名
{
    // ========== 通用赋值工具方法(核心:避免重复代码,保留样式/公式) ==========
    void SetCellValue(int rowIndex, int cellIndex, object value)
    {
        // 1. 获取行(优先用模板已有行,不新建)
        IRow row = sheet.GetRow(rowIndex);
        if (row == null)
        {
            row = sheet.CreateRow(rowIndex);
            // 若新建行,继承模板行高(可选,根据模板调整)
            row.Height = sheet.GetRow(rowIndex)?.Height ?? row.Height;
        }

        // 2. 获取单元格(优先用模板已有单元格,不新建)
        ICell cell = row.GetCell(cellIndex);
        if (cell == null)
        {
            cell = row.CreateCell(cellIndex);
            // 关键:复制模板单元格样式(保留字体/颜色/边框/数字格式)
            ICell templateCell = sheet.GetRow(rowIndex)?.GetCell(cellIndex);
            if (templateCell != null)
            {
                cell.CellStyle = templateCell.CellStyle;
            }
        }

        // 3. 跳过公式单元格(防止覆盖模板公式)
        if (cell.CellType == CellType.Formula)
        {
            return;
        }

        // 4. 安全赋值(处理空值+类型转换)
        try
        {
            switch (value)
            {
                case null:
                    cell.SetCellValue(0); // 空值默认赋值0
                    break;
                case int intVal:
                    cell.SetCellValue(intVal);
                    break;
                case double doubleVal:
                    cell.SetCellValue(doubleVal);
                    break;
                case decimal decimalVal:
                    cell.SetCellValue(Convert.ToDouble(decimalVal));
                    break;
                case string strVal:
                    // 字符串转数值(兼容DTO中string类型的数值字段)
                    if (double.TryParse(strVal, out double strToDouble))
                    {
                        cell.SetCellValue(strToDouble);
                    }
                    else
                    {
                        cell.SetCellValue(strVal); // 非数值字符串直接赋值
                    }
                    break;
                default:
                    cell.SetCellValue(value.ToString());
                    break;
            }
        }
        catch (Exception ex)
        {
            // 赋值异常兜底(避免单个单元格错误导致整体失败)
            cell.SetCellValue(0);
            // 可选:记录日志
            // LogHelper.Error($"单元格[{rowIndex},{cellIndex}]赋值失败:{ex.Message}");
        }
    }
}

对字段进行赋值之后需要手动刷新,才能让列表中公式执行,并在导出内容中展示计算结果

                // 1. 获取公式求值器
                IFormulaEvaluator evaluator = xssfWorkbook.GetCreationHelper().CreateFormulaEvaluator();

                // 2. 刷新所有公式
                evaluator.EvaluateAll(); // 这一步会计算所有公式的当前值

                using (var fileStream = new FileStream(strFile, FileMode.Create, FileAccess.Write))
                {
                    xssfWorkbook.Write(fileStream);
                    // 强制刷新缓冲区,确保完整写入
                    fileStream.Flush();
                }

                // 释放资源(避免内存泄漏)
                xssfWorkbook.Close();

More info: Learnerping的个人微博

posted @ 2025-12-19 15:38  LearnerPing  阅读(0)  评论(0)    收藏  举报