NPOI插件的弊端
刚来公司的时候公司软件导入导出操作都使用微软的office组件来实现,大家应该都知道这个组件有很大的弊端,就是运行主机上面必须安装office组件才可进行使用,不然无法进行导入导出操作,之前公司软件部门给的做法就是直接让客户安装Office就可以解决。
我接手后知道这个弊端,将插件进行了替换,使用网上比较流行的NPOI插件,基本上很少出现关于软件导入导出数据的反馈。
但由于之前的软件需求基本都是少量数据的导入导出,NPOI都可以满足,现在新需求要求导入导出超过40w行的数据,NPOI插件就暴露出来弊端,在数据少的时候使用.xlsx的XFFSWorkbook类就可以实现,但是数据量超过某一个阀值,XFFSWorkbook就出现了异常,爆出内存溢出的消息,而且声明和访问时速度特别慢,感觉是组件内部在处理大数据文件时存在问题。
在网上查找发现NPOI对于大数据的处理有一个SXSSFWorkbook,它是NPOI专门来处理大数据文件的,我在使用过程中,当写入时,没问题可以使用,但是效率方面很差。可是在读取时,根本无法使用,因为它在使用过程中必须声明XFFWorkbook才可以,可是声明它的话就会遇到内存溢出问题。网上还有说直接使用xml形式来读取,但是xml格式需要自己去定义和解析,特别麻烦,故没有采用。
//声明处理.xlsx文件的方法(小文件) IWorkbook workbook=new XSSFWorkbook(); //声明处理.xlsx文件的方法(大文件) IWorkbook workbook=new XSSFWorkbook(); IWorkbook wb=new SXSSFWorkbook(workbook);
ExcelDataReader插件
在处理读取.xlsx文件时,在nuget中发现了ExcelDataReader插件,在做了demo后,对于40w行的读取很方便,而且速度特别快。推荐大家使用。
FileStream fs = null; IExcelDataReader excelReader = null; try { fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs); int readIndex = 0; int rowCount = excelReader.RowCount; //所有的行 DataRow dr; object tempValue; while (excelReader.Read()) { dr = data.NewRow(); if (readIndex == startReadRowCount) { ++readIndex; continue; } //读取Excel中的头文件信息 if (readIndex <startReadRowCount) { dr[0] = excelReader.GetValue(0).ToString(); tempValue = excelReader.GetValue(1); if (tempValue==null) { dr[1] = DBNull.Value; } else { dr[1] = excelReader.GetValue(1).ToString(); } dr[2] = DBNull.Value; dr[3] = DBNull.Value; dr[4] = DBNull.Value; dr[5] = DBNull.Value; dr[6] = DBNull.Value; } else { dr[0] = excelReader.GetValue(0).ToString(); dr[1] = excelReader.GetValue(1).ToString(); dr[2] = Convert.ToDouble(excelReader.GetValue(2)); tempValue = excelReader.GetValue(3); if (tempValue == null) { dr[3] = DBNull.Value; } else { dr[3] = Convert.ToDouble(excelReader.GetValue(3)); } dr[4] = Convert.ToDouble(excelReader.GetValue(4)); dr[5] = Convert.ToDouble(excelReader.GetValue(5)); dr[6] = Convert.ToDouble(excelReader.GetValue(6)); } data.Rows.Add(dr); if (worker.CancellationPending) // 如果用户取消则跳出处理数据代码 { e.Cancel = true; break; } worker.ReportProgress(readIndex * 100 / rowCount);//加载进度条 ++readIndex; } fs.Close(); fs.Dispose(); excelReader.Close(); excelReader.Dispose(); return data; } catch (Exception ex) { if (worker.CancellationPending) // 如果用户取消则跳出处理数据代码 { e.Cancel = true; } if (fs != null) { fs.Close(); fs.Dispose(); } if (excelReader != null) { excelReader.Close(); excelReader.Dispose(); } throw new Exception("" + ex.Message); }