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<string> lstSheetNames = new List<string>();
  4:  for (int i = 0; i < schemaTable.Rows.Count; i++)
  5:  {
  6:      string strSheetName = (string)dtSheetName.Rows[i]["TABLE_NAME"];