C#中使用NPOI解析xls,xlsx文件,对于小的文件没什么问题,但是文件一旦超过30M,经常出现OutOfMemory问题,尤其是连续导入多个大的excel文件,后面导的频繁出现OOM问题,于是手动调试看看哪一步使用导致内存大量被占用,仔细观察内存的变化,发现在创建WorkBook的时候,内存使用迅速上升,本来20多M的Excel,创建workbook内存消耗1.8G左右,在读取完成之后,内存并没有立即释放出来,而是等了大概1分多钟的样子,内存才渐渐释放出来,这样如果多次导入excel,后面导入的很可能就会出现OOM了,这可能是NPOI的问题吧。
目前在网上看到MiniExcel,看起来很不错,不用把整个excel加载到内存,能有效避免OOM的问题,学习地址:MiniExcel学习文档
1、安装MiniExcel
在NuGet中搜索miniexcel,直接安装依赖包即可
2、获取excel中所有的sheet名字
var sheetNames = MiniExcel.GetSheetNames(path);
3、获取某个sheet中所有的行数据
var rows = MiniExcel.Query(path, true, sheetName);
4、获取某个sheet中的所有列名
var columns = MiniExcel.GetColumns(path, true, sheetName);
5、遍历所有数据
foreach (var row in _rows)
{
DataRow dataRow = dataTable.NewRow();
dataRow["A"] = row.A;
dataRow["B"] = row.B;
dataRow["C"] = row.C;
dataRow["D"] = row.D;
dataRow["E"] = row.E;
dataRow["F"] = DBNull.Value;
dataRow["G"] = row.G;
dataRow["H"] = row.H;
dataTable.Rows.Add(dataRow);
}
6、WinForm中实现数据解析进度条计算逻辑
先计算有多少个sheet,按100分成对应的等份,记为A,然后计算每个sheet的记录总数,假如按照100000条记录来分页,计算能分成多少页,再按照每个sheet所占的等份A,继续分成每页需要的等份,记为B,然后解析完一页数据,就将进度增加B,然后更新进度条控件的值就好了。
注意:在线程中更新进度条的操作是不允许的,可以通过控件的Invoke方法实现更新。
private void RefreshPercent(int percent)
{
this.progressBar1.Invoke(new Action(() =>
{
this.progressBar1.Value = percent;
this.labelper.Text = percent + "%";
if (percent == 100)
this.dataImportBtn.Enabled = true;
}));
}
这里数据批量保存采用存储过程的方式,代码端需要传递DataTable类型的参数,数据库端需要定义字段名称和个数一致的用户自定义表类型,用于接收参数,然后在存储过程写保存数据逻辑。