那些天使用NPOI走过的坑

本文主要介绍我用NPOI生成Excel文件所报过的错,以及是如何解决的。

目录

内容未写入

文件流是否有问题

是否存在该单元格

表格中已编辑好的公式不生效

进程被占用

检查FileStream是否关闭

检查FileStream是否被重复调用

保存大量数据时,内存溢出

分批次导入,每次保存时都释放内存


内容未写入

你是否也遇到过这样的情况,代码不报错、跟着断点走,内容也还是在,但是一打开Excel里面空空如也。此时,你可以检查以下几个地方。

  • 文件流是否有问题

写入时总共要两个FileStream,一个用于给RWorkbook赋值,一个用于写入(注意我们这里使用的是File.Create,用File.OpenWrite也会导致不成功)。如下列代码所示

static IWorkbook RWorkbook = null;
        //给workBook赋值
        public static void initWorkBook()
        {
            using (FileStream fs = new FileStream(QueryParm.filePath, FileMode.Open, FileAccess.ReadWrite))
            {
                try
                {
                    RWorkbook = new XSSFWorkbook(fs);
                }
                catch (Exception e)
                {
                    //出错执行的代码...
                }
            }
        }

        //写入
        public static void SaveExcel()
        {
            using (FileStream fsWrite = File.Create(QueryParm.filePath))
            {
                try
                {
                    RWorkbook.Write(fsWrite);
                }
                catch (IOException e)
                {
                    //出错执行的代码...
                }
            }

        }
  • 是否存在该单元格

当我们编辑单元格内容时,首先需要确保能够获取到该单元格。然而,有时我们可能会忽略确认单元格是否存在。尽管我们肉眼可以看到单元格,但可能无法对其进行操作。如果手动编辑该单元格并使用代码覆盖它,则可以成功编写。因此,在此处我们需要进行判断。如果无法获取该单元格,则直接创建一个新的单元格(对于已有格式的表格),而对于空表格,则无需进行判断并直接创建一个新的单元格。如下列代码所示

//省略获取sheet的代码....            

//获取单元格行数,row为行数
 IRow sheetRow = sheet.GetRow(row);
 if (sheetRow == null)
    {
        sheetRow = sheet.CreateRow(row);
    }

//获取单元格,col为列数
  ICell sheetCell = sheetRow.GetCell(col);
  if (sheetCol == null)
    {
        sheetCell = sheetRow.CreateCell(col);
    }

//若果说我要修改第二行第三列的单元格则把row改为2,col改为3
  sheetCell .SetCellValue("修改的内容");
  • 表格中已编辑好的公式不生效

 表格文件中已经定好了函数公式,通过NPOI把数据写入文件后,公式没有被触发。首先我们要先检查数据类型,写进去的是int还是string;其次修改后将ISheet的ForceFormulaRecalculation 属性设置为true,如:sheet.ForceFormulaRecalculation = true;

ForceFormulaRecalculation:这是一个 NPOI 的特性,它允许你强制 Excel 重新计算所有单元格的公式。在 HSSFWorkbook 和 NPOI.SS.UserModel.ISheet 中有一个 ForceFormulaRecalculation 属性。设置该属性为 true 可以强制重新计算所有单元格的公式。

进程被占用

  1. 检查FileStream是否关闭

    可以用using将要使用到FileStream的代码部分包起来,这样运行完就会自动释放。

    using (FileStream fs = File.Create(QueryParm.filePath))
    {
        //要用到fs的部分代码
    }
  2. 检查FileStream是否被重复调用

        作者之前就是每改一个单元格的格子就写入一次,从而引发了这个问题。最好的解决方案就是把要改的单元格全部set好后再调用写入的方法,这样不仅能解决解决被占用的问题还能大大提升程序的运行速度。

保存大量数据时,内存溢出

        分批次导入,每次保存时都释放内存

        比如说我们要保存十万条数据,我们可以每3000条保存一次,保存好后可以释放WorkBook的内存,这里需要注意的是,释放内存后记得重新给WorkBook和Sheet赋值,要不然会找不到sheet,

         给WorkBook释放内存我使用的是Workbook.Clear();属性,如果找不到该属性,大概率是版本没有,我测试过Close();,没有效果,我这里使用的是2.0.6.0版本。

                数据处理片段:

//写入数据方法,这里展示的是片段
try
                    {
                        // 创建标题行
                        IRow dataRowTitle = sheet.CreateRow(0);
                        for (int c = 0; c < dt.Columns.Count; c++)
                        {
                            string colName = dt.Columns[c].ColumnName;
                            dataRowTitle.CreateCell(c).SetCellValue(colName);
                        }

                        int counter = 0;

                        for (int i = 0; i < dt.Rows.Count; i++)
                        {
                            IRow dataRow = sheet.CreateRow(i + 1);

                            for (int j = 0; j < dt.Columns.Count; j++)
                            {
                                string content = dt.Rows[i][j].ToString();
                                dataRow.CreateCell(j).SetCellValue(content);
                            }

                            counter += 1;
                            
                            //每3000次和最后一次调用保存的方法
                            if (counter % 3000 == 0 || counter == dt.Rows.Count)
                            {
                                SaveExcel();
                                initWorkBook();
                                sheet = RWorkbook.GetSheet(sheetIndex.ToString());
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        //错误执行片段
                    }

写入Excel片段

public static void SaveExcel()
        {
            using (FileStream fsWrite = File.Create(QueryParm.filePath))
            {
                try
                {
                    RWorkbook.Write(fsWrite);
                }
                catch (IOException e)
                {
                    //错误执行片段
                }
            }

            //清除缓存
            RWorkbook.Clear();
        }

以上就是我的一些报错总结,欢迎留言探讨。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值