C#读取Excel的三种方式以及比较

  • A+
所属分类:C#

C#读取Excel的三种方式以及比较 - jingkun.liu - 博客园

C#读取Excel的三种方式以及比较

(1)OleDB方式

优点:将Excel直接当做数据源处理,通过SQL直接读取内容,读取速度较快。

缺点:读取数据方式不够灵活,无法直接读取某一个单元格,只有将整个Sheet页读取出来后(结果为Datatable)再在Datatable中根据行列数来获取指定的值。

       当Excel数据量很大时。会非常占用内存,当内存不够时会抛出内存溢出的异常。

读取代码如下:

1: public DataTable GetExcelTableByOleDB(string strExcelPath, string tableName)

2: {

3: try

4: {

5: DataTable dtExcel = new DataTable();

6: //数据表

7: DataSet ds = new DataSet();

8: //获取文件扩展名

9: string strExtension = System.IO.Path.GetExtension(strExcelPath);

10: string strFileName = System.IO.Path.GetFileName(strExcelPath);

11: //Excel的连接

12: OleDbConnection objConn = null;

13: switch (strExtension)

14: {

15: case ".xls":

16: objConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + strExcelPath + ";" + "Extended Properties=\"Excel 8.0;HDR=NO;IMEX=1;\"");

17: break;

18: case ".xlsx":

19: objConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + strExcelPath + ";" + "Extended Properties=\"Excel 12.0;HDR=NO;IMEX=1;\"");

20: break;

21: default:

22: objConn = null;

23: break;

24: }

25: if (objConn == null)

26: {

27: return null;

28: }

29: objConn.Open();

30: //获取Excel中所有Sheet表的信息

31: //System.Data.DataTable schemaTable = objConn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);

32: //获取Excel的第一个Sheet表名

33: //string tableName = schemaTable.Rows[0][2].ToString().Trim();

34: string strSql = "select * from [" + tableName + "]";

35: //获取Excel指定Sheet表中的信息

36: OleDbCommand objCmd = new OleDbCommand(strSql, objConn);

37: OleDbDataAdapter myData = new OleDbDataAdapter(strSql, objConn);

38: myData.Fill(ds, tableName);//填充数据

39: objConn.Close();

40: //dtExcel即为excel文件中指定表中存储的信息

41: dtExcel = ds.Tables[tableName];

42: return dtExcel;

43: }

44: catch

45: {

46: return null;

47: }

48: }
下面说明一下连接字符串

    HDR=Yes,这代表第一行是标题,不做为数据使用(但是我在实际使用中,如果第一行存在复杂数值,那么读取得到的Datatable列标题会自动设置为F1、F2等方式命名,与实际应用不符,所以当时是通过HDR=No方式将所有内容读取到Datatable中,然后手动将第一行设置成标题的);IMEX ( IMport EXport mode )设置

IMEX 有三种模式:
0 is Export mode
1 is Import mode
2 is Linked mode (full update capabilities)
我这里特别要说明的就是 IMEX 参数了,因为不同的模式代表著不同的读写行为:
当 IMEX=0 时为“汇出模式”,这个模式开启的 Excel 档案只能用来做“写入”用途。
当 IMEX=1 时为“汇入模式”,这个模式开启的 Excel 档案只能用来做“读取”用途。
当 IMEX=2 时为“链接模式”,这个模式开启的 Excel 档案可同时支援“读取”与“写入”用途。


另外,读取Excel2007版本的文件时,版本应该从8.0改为12.0,同时驱动不能再用Jet,而应该用ACE。负责会造成“找不到可安装的 ISAM”的错误。

在网上还发现采用这种方式存在取出的Sheet表的个数多于实际Excel表中的Sheet表个数的情况,其原因有二:
1. 取出的名称中,包括了XL命名管理器中的名称(参见XL2007的公式--命名管理器, 快捷键Crtl+F3);
2. 取出的名称中,包括了FilterDatabase后缀的, 这是XL用来记录Filter范围的。

对于第一点比较简单, 删除已有命名管理器中的内容即可;第二点处理起来比较麻烦, Filter删除后这些名称依然保留着,简单的做法是新增Sheet然后将原Sheet Copy进去。但实际情况并不能为每个Excel做以上检查。下面给出了过滤的方案。(此问题我们有验证过,大家自己验证一下吧)

1: //objConn为读取Excel的链接,下面通过过滤来获取有效的Sheet页名称集合

2: System.Data.DataTable schemaTable = objConn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);

3: List lstSheetNames = new List();

4: for (int i = 0; i < schemaTable.Rows.Count; i++)

5: {

6: string strSheetName = (string)dtSheetName.Rows[i]["TABLE_NAME"];

7: if (strSheetName.Contains("$") && !strSheetName.Replace("'", "").EndsWith("$"))

8: {

9: //过滤无效SheetName完毕....

10: continue;

11: }

12: if (lstSheetNames != null && !lstSheetNames.Contains(strSheetName))

13: lstSheetNames.Add(strSheetName);

14: }

因为读取出来无效SheetName一般情况最后一个字符都不会是$。如果SheetName有一些特殊符号,读取出来的SheetName会自动加上单引号。比如在Excel中将SheetName编辑成MySheet(1),此时读取出来的SheetName就为:'MySheet(1)

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin