shanzm-2020年12月8日 23:48:11

0. 前言

以前基于 .NET 开发的程序,我一般都是使用NPOI操作Excel文件,

因为我的程序读取的是另外一个成品WMS导出的Excel文件(至于为什么不直接从数据库获取该WMS导出到Excel的数据,此中原因,一言难尽!),在使用NPOI读取Excel的时候,提示错误:

Initialisation of record 0x203(NumberRecord) left 4 bytes remaining still to be read.

StackOverFlow一个高赞答案就是升级NPOI版本,或使用Office Excel将Excel文件另存为,保存为新的Excel文件再使用NPOI读取该Excel文件。

虽已使用最新的NPOI,但是依旧出现该错误,让用户另存为不合适,但是我又尚未找到一个简单有效快速的处理方法。

考虑到服务器上已经安装的Office套件,所以使用Com组件的方法操作Excel文件,但是读取速度较慢。

最终尝试使用ADO .NET 中的OleDbConnection类读取Excel文件,读取速度,且相对方便,简单记录如下。


1. 使用NPOI库读取Excel文件

在.NET程序中需要操作Excel文件,不论xls格式还是xlsx格式都是可以使用NPOI

Nuget获取该扩展:

PM> Install-Package NPOI -Version 2.5.2

简单的一个示例,读取用户上传的Excel文件:

    /// <summary>
/// 读取Excel导入DataTable
/// </summary>
/// <param name="filepath">导入的文件路径(包括文件名)</ param>
/// <param name="sheetName">工作表名称</param>
/// <param name="isFirstRowColumn">第一行是否是DataTable的列 名</param>
/// <returns>DataTable</returns>
public static DataTable ExcelToDataTable(string filePath,string sheetName,bool isFirstRowColumn)
{
DataTable data = new DataTable();
FileStream fs;
int startRow = 0;
using (fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
try
{
IWorkbook workbook = filePath.Contains(".xlsx") ? (IWorkbook)new XSSFWorkbook(fs) :newHSSFWorkbook(fs);//xlsx使用XSSFWorkbook, xls使用HSSFWorkbokk
ISheet sheet = workbook.GetSheet(sheetName) ?? workbook.GetSheetAt(0);//如果没有找到指sheetName 对应的sheet,则尝试获取第一个sheet
if (sheet != null)
{
IRow firstrow = sheet.GetRow(0);//第一行
int firstCellNum = firstrow.FirstCellNum;// 行第一个cell的编号,从0开始
int lastCellNum = firstrow.LastCellNum; // 行最后一个cell的编号 即总的列数,(不忽略中间某 列空格)
if (isFirstRowColumn)//如果第一行是表格列头
{
for (int i = firstCellNum; i < lastCellNum; i++)
{
ICell cell = firstrow.GetCell(i);
if (cell != null)
{
string cellValue = cell.StringCellValue;
if (cellValue != null)
{
DataColumn column = new DataColumn(cellValue);
data.Columns.Add(column);
}
}
}
startRow = sheet.FirstRowNum + 1;
}
else
{
startRow = sheet.FirstRowNum;
}
//读数据行
int rowCont = sheet.LastRowNum;
for (int i = startRow; i <=rowCont; i++)
{
IRow row = sheet.GetRow(i);
DataRow dataRow = data.NewRow();
//判断需要读取的最后一行
if (row != null && (row.GetCell(row.FirstCellNum) != null && row.GetCel (rowFirstCellNum).ToString() != "合计") )
{
for (int j = row.FirstCellNum; j < lastCellNum; j++)
{
dataRow[j] = row.GetCell(j).ToString();
}
data.Rows.Add(dataRow);
}
else
{
break;
}
}
}
return data;
}
catch (Exception ex)
{
Debug.WriteLine("Exception: " + ex.Message);
return null;
}
finally
{
fs.Close();
fs.Dispose();
}
}
}

读取到Excel表格中的数据到DataTable 中,可以使用SqlBulkCopy批量插入的方式将DataTable数据存储到数据库表中,关于ADO .NET 针对SQL Server的批量插入的各种方法以及比较,可以参考文末给出的参考连接

简单示例如下:

        /// <summary>
/// 使用SqlBulkCopy将DataTable中的数据批量插入数据库中
/// 注意:DataTable中的列需要与数据库表中的列完全一致。
/// </summary>
/// <param name="conStr">数据库连接串</param>
/// <param name="dbTableName">数据库中对应的表名</param>
/// <param name="dtData">数据集</param>
public static void SqlBulkCopyInsert(string dbTableName, DataTable dataTable)
{
using (SqlBulkCopy sqlRevdBulkCopy = new SqlBulkCopy(connStr))//引用SqlBulkCopy
{
sqlRevdBulkCopy.DestinationTableName = dbTableName;//数据库中对应的表名
sqlRevdBulkCopy.NotifyAfter = dataTable.Rows.Count;//有几行数据
sqlRevdBulkCopy.WriteToServer(dataTable);//数据导入数据库
sqlRevdBulkCopy.Close();//关闭连接
}
}

2. 使用OleDbConnection

使用ADO .NET 中的OleDbConnection类连接查询。简单示例如下:

        /// <summary>
/// 读取Excel返回DataTable
/// </summary>
/// <param name="filePath">Excel文件路径</param>
/// <param name="tableName">Excel文件中Sheet名称</param>
/// <returns></returns>
public static DataSet ExcelToDataSet(string filePath, string tableName)
{
//获取文件扩展名
string strExtension = System.IO.Path.GetExtension(filePath);
OleDbConnection myConn = null;
switch (strExtension)
{
case ".xls":
myConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath + ";" + "Extended Properties=\"Excel 8.0;HDR=yes;IMEX=1;\"");
break;
case ".xlsx":
myConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";" + "Extended Properties=\"Excel 12.0;HDR=yes;IMEX=1;\"");
//此连接可以操作.xls与.xlsx文件 (支持Excel2003 和 Excel2007 的连接字符串)
//"HDR=yes;"是说Excel文件的第一行是列名而不是数,"HDR=No;"正好与前面的相反。"IMEX=1 "如果列中的数据类型不一致,使用"IMEX=1"可必免数据类型冲突。
break;
default:
myConn = null;
break;
}
if (myConn == null)
{
return null;
}
string strCom = " SELECT * FROM [" + tableName + "$]";
myConn.Open();
//获取Excel指定Sheet表中的信息
OleDbDataAdapter myCommand = new OleDbDataAdapter(strCom, myConn);
DataSet ds;
ds = new DataSet();
myCommand.Fill(ds, tableName);
myConn.Close();
return ds.Tables[0];
}

使用OleDbConnection在本地测试没有问题,在发布部署在服务器后出现了一个异常:

未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序

解决方法:IIS-->应用程序池-->选中部署的项目右键-->高级设置-->启用32位应用程序-->True


3. 相关参考

基于.NET的程序读取Excel文件的解决方案的更多相关文章

  1. C#读取excel文件提示未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序

    错误描述: 在VS2010执行读取excel文件时,报错"未在本地计算机上注册"Microsoft.ACE.OLEDB.12.0"提供程序" 业务代码: //下 ...

  2. 项目一:第四天 1、快递员的条件分页查询-noSession,条件查询 2、快递员删除(逻辑删除) 3、基于Apache POI实现批量导入区域数据 a)Jquery OCUpload上传文件插件使用 b)Apache POI读取excel文件数据

    1. 快递员的条件分页查询-noSession,条件查询 2. 快递员删除(逻辑删除) 3. 基于Apache POI实现批量导入区域数据 a) Jquery OCUpload上传文件插件使用 b) ...

  3. .Net读取Excel文件时丢失数据的问题 (转载)

    相信很多人都试过通过OleDB读取Excel文件,这种方法效率十分高,只是有一点会让人十分头痛,就是当一列中既有混合型数据,又有纯数据时,往往容易丢失数据. 百度过后,改连接字符串 “HDR=YES; ...

  4. 读取Excel文件的两种方法

    第一种方法:传统方法,采用OleDB读取EXCEL文件, 优点:写法简单,缺点:服务器必须安有此组件才能用,不推荐使用 private DataSet GetConnect_DataSet2(stri ...

  5. PhpSpreadsheet如何读取excel文件

    PhpSpreadsheet如何读取excel文件 一.总结 一句话总结:万能的百度,直接搜代码就好,绝对有,毕竟github上面4000+的关注,说明很多人用了这个,使用照着demo倒是异常简单 二 ...

  6. 如何在C#中打开和读取EXCEL文件

    这篇文章向您展示如何在C#Windows Forms Application中使用ExcelDataReader,ExcelDataReader.DataSet打开和读取Excel文件.创建一个新的W ...

  7. C# 读取EXCEL文件的三种经典方法

    1.方法一:采用OleDB读取EXCEL文件: 把EXCEL文件当做一个数据源来进行数据的读取操作,实例如下: public DataSet ExcelToDS(string Path) { stri ...

  8. c# .Net :Excel NPOI导入导出操作教程之读取Excel文件信息及输出

    c# .Net :Excel NPOI导入导出操作教程之读取Excel文件信息及输出 using NPOI.HSSF.UserModel;using NPOI.SS.UserModel;using S ...

  9. ADO.NET 读取Excel文件,并作数据源

    项目中需要用的功能,贴上代码了. 需要注意的地方:配置Web.config的时候要注意版本问题! //若是在Web.config中配置数据源,如下 <add key="ExcelCon ...

随机推荐

  1. 机器学习-对数logistics回归

    今天 学习了对数几率回归,学的不是很明白x1*theat1+x2*theat2...=y 对于最终的求解参数编程还是不太会,但是也大致搞明白了,对数几率回归是由于线性回归函数的结果并不是我们想要的,我 ...

  2. Kafka 生产者分区策略

    分区策略 1)分区的原因 (1)方便在集群中扩展,每个 Partition 可以通过调整以适应它所在的机器,而一个 topic 又可以有多个 Partition 组成,因此整个集群就可以适应任意大小的 ...

  3. Python项目2:弹幕复读机

    目录 一.功能 二.思路 三.实现 1. 获取弹幕 2. 发送弹幕 3. 封装调用 这个项目是我从B站的一个up主那学到的(原视频号269525280),感觉很是有趣,就是很欠打哈哈 一.功能 功能很 ...

  4. python之路《八》装饰器

    装饰器是个好东西啊 那么装饰器是个什么样的东西呢,他又能做些什么呢? 1.为什么装饰器 当我们一个程序已经构建完成,并且已经发布出去了,但是现在需要增加一个活动,例如淘宝给你发送一个今日优惠,或者开启 ...

  5. ceph写osd的配置文件/etc/ceph/ceph.conf

    ceph在部署过程中是先进行部署,再去写配置文件的,而一些新手在部署完了后,并没有写配置文件,在重启服务器后,因为挂载点没有挂载,所以服务无法启动,所以需要写好配置文件 还有一种情况是集群有几百个os ...

  6. php(tp5) 生成二维码

    phpqrcode类库官网下载地址:https://sourceforge.net/projects/phpqrcode/ 1.我们先看看php是怎么生成二维码的 1.首先我们先下载一下  phpqr ...

  7. MindManager思维导图应用到办公中需要注意什么

    MindManager思维导图是一个易于使用的项目管理软件,能很好地提高项目组的工作效率和小组成员之间的协作性.接下来,小编就为大家介绍三个能利用好该思维导图软件办公的技巧. 一.审阅会议--合作办公 ...

  8. 教你用Camtasia制作精美片头

    大家都知道在视频播放中,如果有一个令人印象深刻的精彩开头,整个视频的内容都能因此得到不少升华.所以有一个好的片头对于视频的制作来说十分重要.今天我们就来讲一下用Camtasia制作片头的方法. 首先, ...

  9. guitar pro系列教程(二十三):如何使用Guitar Pro制作扫弦

    前面的章节小编和大家讲解了很多关于Guitar Pro的使用功能,本章节我们将还是采用图文结合的方式和大家讲解如何使用Guitar Pro 制作扫弦,感兴趣的朋友可以进来看看哦. 扫弦的概念 对于很多 ...

  10. 关于Java中的内存屏障

    如何打破双亲委派机制 继承ClassLoader类后重写loadClass方法 如何指定自定义ClassLoader中的parent 默认parent是appClassLoader,可以通过Class ...