c# 讀取excel數據的兩種方法


轉載自:http://developer.51cto.com/art/201302/380622.htm

方法一:OleDb: 用這種方法讀取Excel速度還是非常的快的,但這種方式讀取數據的時候不太靈活,不過可以在 DataTable 中對數據進行一些刪減修改。

優點:讀取方式簡單、讀取速度快

缺點:除了讀取過程不太靈活之外,這種讀取方式還有個弊端就是,當Excel數據量很大時。會非常占用內存,當內存不夠時會拋出內存溢出的異常。

不過一般情況下還是非常不錯的。

(代碼比原文相較有所修改)

DataTable GetDataFromExcelByConn(bool hasTitle = false)
{
    OpenFileDialog openFile = new OpenFileDialog();
    openFile.Filter = "Excel(*.xlsx)|*.xlsx|Excel(*.xls)|*.xls";
    openFile.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    openFile.Multiselect = false;
    if (openFile.ShowDialog() == DialogResult.Cancel) return null;
    var filePath = openFile.FileName;
    string fileType = System.IO.Path.GetExtension(filePath);
    if (string.IsNullOrEmpty(fileType)) return null;

    using (DataSet ds = new DataSet())
    {
        string strCon = string.Format("Provider=Microsoft.Jet.OLEDB.{0}.0;" +
                        "Extended Properties=\"Excel {1}.0;HDR={2};IMEX=1;\";" +
                        "data source={3};",
                        (fileType == ".xls" ? 4 : 12), (fileType == ".xls" ? 8 : 12), (hasTitle ? "Yes" : "NO"), filePath);
        string strCom = " SELECT * FROM [Sheet1$]";
        using (OleDbConnection myConn = new OleDbConnection(strCon))
        using (OleDbDataAdapter myCommand = new OleDbDataAdapter(strCom, myConn))
        {
            myConn.Open();
            myCommand.Fill(ds);
        }
        if (ds == null || ds.Tables.Count <= 0) return null;
        return ds.Tables[0];
    }
}
View Code

 

方法二:Com組件的方式讀取Excel 

這種方式需要先引用 Microsoft.Office.Interop.Excel 。首選說下這種方式的優缺點 

優點:可以非常靈活的讀取Excel中的數據 

缺點:如果是Web站點部署在IIS上時,還需要服務器機子已安裝了Excel,有時候還需要為配置IIS權限。最重要的一點因為是基於單元格方式讀取的,所以數據很慢(曾做過試驗,直接讀取千行、200多列的文件,直接讀取耗時15分鍾。即使采用多線程分段讀取來提高CPU的利用率也需要8分鍾。PS:CPU I3) 

需要讀取大文件的的童鞋們慎重。。。

(代碼比原文相較有所修改)

DataTable GetDataFromExcelByCom(bool hasTitle = false)
{
    OpenFileDialog openFile = new OpenFileDialog();
    openFile.Filter = "Excel(*.xlsx)|*.xlsx|Excel(*.xls)|*.xls";
    openFile.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    openFile.Multiselect = false;
    if (openFile.ShowDialog() == DialogResult.Cancel) return null;
    var excelFilePath = openFile.FileName;

    Excel.Application app = new Excel.Application();
    Excel.Sheets sheets;
    object oMissiong = System.Reflection.Missing.Value;
    Excel.Workbook workbook = null;
    DataTable dt = new DataTable();

    try
    {
        if (app == null) return null;
        workbook = app.Workbooks.Open(excelFilePath, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong,
            oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong);
        sheets = workbook.Worksheets;

        //將數據讀入到DataTable中
        Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);//讀取第一張表  
        if (worksheet == null) return null;

        int iRowCount = worksheet.UsedRange.Rows.Count;
        int iColCount = worksheet.UsedRange.Columns.Count;
        //生成列頭
        for (int i = 0; i < iColCount; i++)
        {
            var name = "column" + i;
            if (hasTitle)
            {
                var txt = ((Excel.Range)worksheet.Cells[1, i + 1]).Text.ToString();
                if (!string.IsNullOrWhiteSpace(txt)) name = txt;
            }
            while (dt.Columns.Contains(name)) name = name + "_1";//重復行名稱會報錯。
            dt.Columns.Add(new DataColumn(name, typeof(string)));
        }
        //生成行數據
        Excel.Range range;
        int rowIdx = hasTitle ? 2 : 1;
        for (int iRow = rowIdx; iRow <= iRowCount; iRow++)
        {
            DataRow dr = dt.NewRow();
            for (int iCol = 1; iCol <= iColCount; iCol++)
            {
                range = (Excel.Range)worksheet.Cells[iRow, iCol];
                dr[iCol - 1] = (range.Value2 == null) ? "" : range.Text.ToString();
            }
            dt.Rows.Add(dr);
        }
        return dt;
    }
    catch { return null; }
    finally
    {
        workbook.Close(false, oMissiong, oMissiong);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
        workbook = null;
        app.Workbooks.Close();
        app.Quit();
        System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
        app = null;
    }
}
View Code

原文的方法二還提供了多線程處理數據的代碼,一並復制到此(此處出現了一個SheetOptions的類型,無法考證其來源,如果知曉,請留言,謝謝。):

/// <summary>  
/// 使用COM,多線程讀取Excel(1 主線程、4 副線程)  
/// </summary>  
/// <param name="excelFilePath">路徑</param>  
/// <returns>DataTabel</returns>  
public System.Data.DataTable ThreadReadExcel(string excelFilePath)
{
    Excel.Application app = new Excel.Application();
    Excel.Sheets sheets = null;
    Excel.Workbook workbook = null;
    object oMissiong = System.Reflection.Missing.Value;
    System.Data.DataTable dt = new System.Data.DataTable();

    try
    {
        if (app == null)
        {
            return null;
        }

        workbook = app.Workbooks.Open(excelFilePath, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, 
            oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong);

        //將數據讀入到DataTable中——Start    
        sheets = workbook.Worksheets;
        Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);//讀取第一張表  
        if (worksheet == null)
            return null;

        string cellContent;
        int iRowCount = worksheet.UsedRange.Rows.Count;
        int iColCount = worksheet.UsedRange.Columns.Count;
        Excel.Range range;

        //負責列頭Start  
        DataColumn dc;
        int ColumnID = 1;
        range = (Excel.Range)worksheet.Cells[1, 1];
        //while (range.Text.ToString().Trim() != "")  
        while (iColCount >= ColumnID)
        {
            dc = new DataColumn();
            dc.DataType = System.Type.GetType("System.String");

            string strNewColumnName = range.Text.ToString().Trim();
            if (strNewColumnName.Length == 0) strNewColumnName = "_1";
            //判斷列名是否重復  
            for (int i = 1; i < ColumnID; i++)
            {
                if (dt.Columns[i - 1].ColumnName == strNewColumnName)
                    strNewColumnName = strNewColumnName + "_1";
            }

            dc.ColumnName = strNewColumnName;
            dt.Columns.Add(dc);

            range = (Excel.Range)worksheet.Cells[1, ++ColumnID];
        }
        //End  

        //數據大於500條,使用多進程進行讀取數據  
        if (iRowCount - 1 > 500)
        {
            //開始多線程讀取數據  
            //新建線程  
            int b2 = (iRowCount - 1) / 10;
            DataTable dt1 = new DataTable("dt1");
            dt1 = dt.Clone();
            SheetOptions sheet1thread = new SheetOptions(worksheet, iColCount, 2, b2 + 1, dt1);
            Thread othread1 = new Thread(new ThreadStart(sheet1thread.SheetToDataTable));
            othread1.Start();

            //阻塞 1 毫秒,保證第一個讀取 dt1  
            Thread.Sleep(1);

            DataTable dt2 = new DataTable("dt2");
            dt2 = dt.Clone();
            SheetOptions sheet2thread = new SheetOptions(worksheet, iColCount, b2 + 2, b2 * 2 + 1, dt2);
            Thread othread2 = new Thread(new ThreadStart(sheet2thread.SheetToDataTable));
            othread2.Start();

            DataTable dt3 = new DataTable("dt3");
            dt3 = dt.Clone();
            SheetOptions sheet3thread = new SheetOptions(worksheet, iColCount, b2 * 2 + 2, b2 * 3 + 1, dt3);
            Thread othread3 = new Thread(new ThreadStart(sheet3thread.SheetToDataTable));
            othread3.Start();

            DataTable dt4 = new DataTable("dt4");
            dt4 = dt.Clone();
            SheetOptions sheet4thread = new SheetOptions(worksheet, iColCount, b2 * 3 + 2, b2 * 4 + 1, dt4);
            Thread othread4 = new Thread(new ThreadStart(sheet4thread.SheetToDataTable));
            othread4.Start();

            //主線程讀取剩余數據  
            for (int iRow = b2 * 4 + 2; iRow <= iRowCount; iRow++)
            {
                DataRow dr = dt.NewRow();
                for (int iCol = 1; iCol <= iColCount; iCol++)
                {
                    range = (Excel.Range)worksheet.Cells[iRow, iCol];
                    cellContent = (range.Value2 == null) ? "" : range.Text.ToString();
                    dr[iCol - 1] = cellContent;
                }
                dt.Rows.Add(dr);
            }

            othread1.Join();
            othread2.Join();
            othread3.Join();
            othread4.Join();

            //將多個線程讀取出來的數據追加至 dt1 后面  
            foreach (DataRow dr in dt.Rows)
                dt1.Rows.Add(dr.ItemArray);
            dt.Clear();
            dt.Dispose();

            foreach (DataRow dr in dt2.Rows)
                dt1.Rows.Add(dr.ItemArray);
            dt2.Clear();
            dt2.Dispose();

            foreach (DataRow dr in dt3.Rows)
                dt1.Rows.Add(dr.ItemArray);
            dt3.Clear();
            dt3.Dispose();

            foreach (DataRow dr in dt4.Rows)
                dt1.Rows.Add(dr.ItemArray);
            dt4.Clear();
            dt4.Dispose();

            return dt1;
        }
        else
        {
            for (int iRow = 2; iRow <= iRowCount; iRow++)
            {
                DataRow dr = dt.NewRow();
                for (int iCol = 1; iCol <= iColCount; iCol++)
                {
                    range = (Excel.Range)worksheet.Cells[iRow, iCol];
                    cellContent = (range.Value2 == null) ? "" : range.Text.ToString();
                    dr[iCol - 1] = cellContent;
                }
                dt.Rows.Add(dr);
            }
        }
        //將數據讀入到DataTable中——End  
        return dt;
    }
    catch
    {
        return null;
    }
    finally
    {
        workbook.Close(false, oMissiong, oMissiong);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
        workbook = null;
        app.Workbooks.Close();
        app.Quit();
        System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
        app = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
View Code

 

補充SheetOptions代碼:

class SheetOptions
{
    Microsoft.Office.Interop.Excel.Worksheet worksheet;
    int iColCount;
    int star;
    int end;
    System.Data.DataTable dt;
    public SheetOptions(Microsoft.Office.Interop.Excel.Worksheet worksheet, int iColCount, int star, int end, System.Data.DataTable dt)
    {
        this.worksheet = worksheet;
        this.iColCount = iColCount;
        this.star = star;
        this.end = end;
        this.dt = dt;
    }

    public void SheetToDataTable()
    {
        string cellContent;
        Microsoft.Office.Interop.Excel.Range range;
        for (int iRow = star; iRow <= end; iRow++)
        {
            System.Data.DataRow dr = dt.NewRow();
            for (int iCol = 1; iCol <= iColCount; iCol++)
            {
                range = (Microsoft.Office.Interop.Excel.Range)worksheet.Cells[iRow, iCol];
                cellContent = (range.Value2 == null) ? "" : range.Text.ToString();
                dr[iCol - 1] = cellContent;
            }
            dt.Rows.Add(dr);
        }
    }
}
View Code

 

原文還提供了第三種方法,感興趣的可以關心一下:

方法三:NPOI方式讀取Excel,NPOI是一組開源的組件,類似Java的 POI。包括:NPOI、NPOI.HPSF、NPOI.HSSF、NPOI.HSSF.UserModel、NPOI.POIFS、NPOI.Util,下載的時候別只下一個噢

優點:讀取Excel速度較快,讀取方式操作靈活性

缺點:只支持03的Excel,xlsx的無法讀取。由於這點,使用這種方式的人不多啊,沒理由要求客戶使用03版Excel吧,再說03版Excel對於行數還有限制,只支持65536行。

(聽他們的開發人員說會在2012年底推出新版,支持xlsx的讀取。但一直很忙沒時間去關注這個事情,有興趣的同學可以瞧瞧去)

  1 using System;
  2 using System.Data;
  3 using System.IO;
  4 using System.Web;
  5 using NPOI;
  6 using NPOI.HPSF;
  7 using NPOI.HSSF;
  8 using NPOI.HSSF.UserModel;
  9 using NPOI.POIFS;
 10 using NPOI.Util;
 11 using System.Text;
 12 using System.Configuration;
 13 
 14 public class NPOIHelper
 15 {
 16     private static int ExcelMaxRow = Convert.ToInt32(ConfigurationManager.AppSettings["ExcelMaxRow"]);
 17     /// <summary>  
 18     /// 由DataSet導出Excel  
 19     /// </summary>  
 20     /// <param name="sourceTable">要導出數據的DataTable</param>     
 21     /// <param name="sheetName">工作表名稱</param>  
 22     /// <returns>Excel工作表</returns>     
 23     private static Stream ExportDataSetToExcel(DataSet sourceDs)
 24     {
 25         HSSFWorkbook workbook = new HSSFWorkbook();
 26         MemoryStream ms = new MemoryStream();
 27 
 28         for (int i = 0; i < sourceDs.Tables.Count; i++)
 29         {
 30             HSSFSheet sheet = (HSSFSheet)workbook.CreateSheet(sourceDs.Tables[i].TableName);
 31             HSSFRow headerRow = (HSSFRow)sheet.CreateRow(0);
 32             // handling header.             
 33             foreach (DataColumn column in sourceDs.Tables[i].Columns)
 34                 headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
 35             // handling value.             
 36             int rowIndex = 1;
 37             foreach (DataRow row in sourceDs.Tables[i].Rows)
 38             {
 39                 HSSFRow dataRow = (HSSFRow)sheet.CreateRow(rowIndex);
 40                 foreach (DataColumn column in sourceDs.Tables[i].Columns)
 41                 {
 42                     dataRow.CreateCell(column.Ordinal).SetCellValue(row[column].ToString());
 43                 }
 44                 rowIndex++;
 45             }
 46         }
 47         workbook.Write(ms);
 48         ms.Flush();
 49         ms.Position = 0;
 50         workbook = null;
 51         return ms;
 52     }
 53     /// <summary>  
 54     /// 由DataSet導出Excel  
 55     /// </summary>    
 56     /// <param name="sourceTable">要導出數據的DataTable</param>  
 57     /// <param name="fileName">指定Excel工作表名稱</param>  
 58     /// <returns>Excel工作表</returns>     
 59     public static void ExportDataSetToExcel(DataSet sourceDs, string fileName)
 60     {
 61         //檢查是否有Table數量超過65325  
 62         for (int t = 0; t < sourceDs.Tables.Count; t++)
 63         {
 64             if (sourceDs.Tables[t].Rows.Count > ExcelMaxRow)
 65             {
 66                 DataSet ds = GetdtGroup(sourceDs.Tables[t].Copy());
 67                 sourceDs.Tables.RemoveAt(t);
 68                 //將得到的ds插入 sourceDs中  
 69                 for (int g = 0; g < ds.Tables.Count; g++)
 70                 {
 71                     DataTable dt = ds.Tables[g].Copy();
 72                     sourceDs.Tables.Add(dt);
 73                 }
 74                 t--;
 75             }
 76         }
 77 
 78         MemoryStream ms = ExportDataSetToExcel(sourceDs) as MemoryStream;
 79         HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName);
 80         HttpContext.Current.Response.BinaryWrite(ms.ToArray());
 81         HttpContext.Current.ApplicationInstance.CompleteRequest();
 82         //HttpContext.Current.Response.End();  
 83         ms.Close();
 84         ms = null;
 85     }
 86     /// <summary>  
 87     /// 由DataTable導出Excel  
 88     /// </summary>  
 89     /// <param name="sourceTable">要導出數據的DataTable</param>  
 90     /// <returns>Excel工作表</returns>     
 91     private static Stream ExportDataTableToExcel(DataTable sourceTable)
 92     {
 93         HSSFWorkbook workbook = new HSSFWorkbook();
 94         MemoryStream ms = new MemoryStream();
 95         HSSFSheet sheet = (HSSFSheet)workbook.CreateSheet(sourceTable.TableName);
 96         HSSFRow headerRow = (HSSFRow)sheet.CreateRow(0);
 97         // handling header.       
 98         foreach (DataColumn column in sourceTable.Columns)
 99             headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
100         // handling value.       
101         int rowIndex = 1;
102         foreach (DataRow row in sourceTable.Rows)
103         {
104             HSSFRow dataRow = (HSSFRow)sheet.CreateRow(rowIndex);
105             foreach (DataColumn column in sourceTable.Columns)
106             {
107                 dataRow.CreateCell(column.Ordinal).SetCellValue(row[column].ToString());
108             }
109             rowIndex++;
110         }
111         workbook.Write(ms);
112         ms.Flush();
113         ms.Position = 0;
114         sheet = null;
115         headerRow = null;
116         workbook = null;
117         return ms;
118     }
119     /// <summary>  
120     /// 由DataTable導出Excel  
121     /// </summary>  
122     /// <param name="sourceTable">要導出數據的DataTable</param>  
123     /// <param name="fileName">指定Excel工作表名稱</param>  
124     /// <returns>Excel工作表</returns>  
125     public static void ExportDataTableToExcel(DataTable sourceTable, string fileName)
126     {
127         //如數據超過65325則分成多個Table導出  
128         if (sourceTable.Rows.Count > ExcelMaxRow)
129         {
130             DataSet ds = GetdtGroup(sourceTable);
131             //導出DataSet  
132             ExportDataSetToExcel(ds, fileName);
133         }
134         else
135         {
136             MemoryStream ms = ExportDataTableToExcel(sourceTable) as MemoryStream;
137             HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName);
138             HttpContext.Current.Response.BinaryWrite(ms.ToArray());
139             HttpContext.Current.ApplicationInstance.CompleteRequest();
140             //HttpContext.Current.Response.End();  
141             ms.Close();
142             ms = null;
143         }
144     }
145 
146     /// <summary>  
147     /// 傳入行數超過65325的Table,返回DataSet  
148     /// </summary>  
149     /// <param name="dt"></param>  
150     /// <returns></returns>  
151     public static DataSet GetdtGroup(DataTable dt)
152     {
153         string tablename = dt.TableName;
154 
155         DataSet ds = new DataSet();
156         ds.Tables.Add(dt);
157 
158         double n = dt.Rows.Count / Convert.ToDouble(ExcelMaxRow);
159 
160         //創建表  
161         for (int i = 1; i < n; i++)
162         {
163             DataTable dtAdd = dt.Clone();
164             dtAdd.TableName = tablename + "_" + i.ToString();
165             ds.Tables.Add(dtAdd);
166         }
167 
168         //分解數據  
169         for (int i = 1; i < ds.Tables.Count; i++)
170         {
171             //新表行數達到最大 或 基表數量不足  
172             while (ds.Tables[i].Rows.Count != ExcelMaxRow && ds.Tables[0].Rows.Count != ExcelMaxRow)
173             {
174                 ds.Tables[i].Rows.Add(ds.Tables[0].Rows[ExcelMaxRow].ItemArray);
175                 ds.Tables[0].Rows.RemoveAt(ExcelMaxRow);
176 
177             }
178         }
179 
180         return ds;
181     }
182 
183     /// <summary>  
184     /// 由DataTable導出Excel  
185     /// </summary>  
186     /// <param name="sourceTable">要導出數據的DataTable</param>  
187     /// <param name="fileName">指定Excel工作表名稱</param>  
188     /// <returns>Excel工作表</returns>  
189     public static void ExportDataTableToExcelModel(DataTable sourceTable, string modelpath, string modelName, string fileName, string sheetName)
190     {
191         int rowIndex = 2;//從第二行開始,因為前兩行是模板里面的內容  
192         int colIndex = 0;
193         FileStream file = new FileStream(modelpath + modelName + ".xls", FileMode.Open, FileAccess.Read);//讀入excel模板  
194         HSSFWorkbook hssfworkbook = new HSSFWorkbook(file);
195         HSSFSheet sheet1 = (HSSFSheet)hssfworkbook.GetSheet("Sheet1");
196         sheet1.GetRow(0).GetCell(0).SetCellValue("excelTitle");      //設置表頭  
197         foreach (DataRow row in sourceTable.Rows)
198         {   //雙循環寫入sourceTable中的數據  
199             rowIndex++;
200             colIndex = 0;
201             HSSFRow xlsrow = (HSSFRow)sheet1.CreateRow(rowIndex);
202             foreach (DataColumn col in sourceTable.Columns)
203             {
204                 xlsrow.CreateCell(colIndex).SetCellValue(row[col.ColumnName].ToString());
205                 colIndex++;
206             }
207         }
208         sheet1.ForceFormulaRecalculation = true;
209         FileStream fileS = new FileStream(modelpath + fileName + ".xls", FileMode.Create);//保存  
210         hssfworkbook.Write(fileS);
211         fileS.Close();
212         file.Close();
213     }
214 }
View Code

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM