我們在項目中常常會涉及到對Excel的讀寫操作,而市面上也有很多的操作Excel方式。經過整理常用的是以下幾種方式:
1. COM組件操作Excel讀寫
2. Ado.net方式操作Excel讀寫
3. 開源的第三方組件NPOI
4. Open XML 方式讀寫Excel
上述3種方式其實各有優缺點~,今天這裡是要講述的有關com組件的讀寫Excel操作。
這段時間准備用這3種方式分別體驗下讀寫操作Excel的樂趣,要使用Com組件的方式操作Excel,我們要做的異步首先是要引入相應的Office的dll當然也可以默認從Office的安裝目錄下找到
添加之,因為所有的Com組件操作都需要添加該dll才能進行操作。要注意的一點如果你在開發過程中出現了下面的這種異常
此時你必須將點開剛剛引用的DLL屬性,將其中的Embed Interop Types修改為False, 這樣在創建ExcelApplication類的時候就不會編譯不通過了。
具體原因可見http://blogs.msdn.com/b/mshneer/archive/2009/12/07/interop-type-xxx-cannot-be-embedded-use-the-applicable-interface-instead.aspx
進入正題,簡單來說對於我們一般的操作Excel文檔讀寫,我們只需要了解4個對象,Application, Workbook, Worksheet, Range
1. Application對象: 就是Excel實例,不僅僅是一個Excel文件,而是整體的Excel程序。
2. WorkBook就是實質意義上的某個Excel文件,你可以進行保存操作等等。
3. Worksheet是傳統意義上的某個工作簿類型。
4. Range是我們使用的最多的,你可以理解成一個區域塊,例如常見的"A2:B5"這種表示方式。
更詳細的的概念可以參考微軟的官方文檔 http://msdn.microsoft.com/zh-cn/library/wss56bz7(v=vs.80).aspx
我們可以封裝一個常用的ExcelUtil類來幫助我們通過Com組件的方式操作Excel。
首先,我們就可以動手來從一個Excel的sheet中讀取我們需要的內容,我們可以把控件的引用名先弄短一點,例如這樣:
Excel = Microsoft.Office.Interop.Excel;
聲明下常用的私有變量
Excel.Application excelApplication = saveFilePath = openFilePath = .Empty;
常用的公共屬性
{ { activeSheetIndex = { { excelWorkbook = (excelWorkbook == ) (excelWorkbook.Worksheets == )
傳入Excel文件路徑打開一個Excel文件
OpenExcelApplication( (excelApplication != (.IsNullOrEmpty(path)) Exception( (! Exception(path + excelApplication = == excelWorkbooks.Open(path, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value) = excelWorkbook.Worksheets[activeSheetIndex] = Exception(.Format(
每次操作完Excel都要對Excel中所使用到的對象進項釋放資源的操作如下
= = = = (excelApplication != =
讀取一個Sheet的時候我們一般先要獲取到相應的當前的Worksheet對象,然後從這個Worksheet對象中獲取到相應的Range對象例如從A1:C7等
主要的代碼如下,獲取到當前有效的ActiveIndex,對應的worksheet對象
Excel.Worksheet activeWorksheet = excelWorkbook.Worksheets[activeIndex] (activeWorksheet == = activeWorksheet.Activate();
Excel.Range excelRange = activeWorksheet.get_Range(, );
這裡可能有人會用到說想要知道哪些行列的區域邊界裡面是有數據的其實這裡它自帶提供了2種方式可以獲得當前有數據的區塊Range范圍(默認從A1開始)
ExcelRange GetCurrentRegion( == 構造方法 .Row = .Column = 公共屬性 Row { ; Column { ;
此處的startRange對象就是默認以左上角的哪個Cell坐標當成起始位置,獲得知道當前右下角的最後一個Cell的坐標例如此處的C3
另外一種方法
activeSheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Missing.Value).Activate(); //此處的xlCellTypeLastCell是重點獲取到最後一個有下角的坐標。 Excel.Application excelApp = ((activeSheet.Parent Excel.Workbook).Parent ==
這裡不建議使用他自帶的UsedRange.Row和UsedRange.Column屬性是因為它們十分坑爹的把你曾經使用過的元素所在的范圍也包含進去了,也就是說如果你曾經在D3寫過東西後來又擦掉使用空白的情況下UsedRange屬性計算的是原來的范圍,而這往往不是我們所要的
接下來接著上面我們獲取到Range元素後最重要的一步就是對他進行操作了獲取數據的操作了這是獲取一個單元格的值的操作
//row,column分別是值cell所在的行和列,默認從1開始
string cellValue = (excelRange.Cells[row, col] Excel.Range) == ? .Empty : (excelRange.Cells[row, col] Excel.Range).Value;
如果要獲取到當前這個Range范圍內所有的元素呢我們就需要循環對應的行和咧,如下
( row = ; row <= excelRange.Rows.Count; row++ ( col = ; col <= excelRange.Columns.Count; col++= (excelRange.Cells[row, col] Excel.Range) == ? .Empty : (excelRange.Cells[row, col]
而這裡有個很大的弊端就是效率,看了網上很多用COM組件操作的方法說使用COM組件操作讀寫的效率很低,其實他可以一點也不低。主要因為我們再循環中一次次的操作了Excel的Range對象然後在獲取他的Value對象這樣十分耗損資源,後來在網上找到了解決方案一句話就疏通了整個案情啊~在很早的一篇小馬哥的博客中找到了答案 http://www.cnblogs.com/maweifeng/archive/2005/06/28/182483.html
其實我們的Range對象可以和數組進行很好的互操作性,我們其實每次只需要把當前要獲取的Range區域元素賦值給一個二維數組然後對二維數組在進行相應的循環讀取或者寫入操作,這速度的提升是飛一般的感覺啊~
我用Stopwatch監視了下,寫入一個5000行10列的數據用Range的方式讀取元素花了94880ms相當於1分30幾秒,而轉用二維數組的方式後只用4秒,這個差距其實是很大的
所以建議我們真的要使用COM來操作Excel的朋友可以用數組的方式來操作讀寫
[,] dataValueRange = = ( row = ; row <= rowCount; row++ ( col = ; col <= columnCount; col++= dataValueRange[row, col] == ?
對於寫入Excel其實上面的步驟也是相同的
只是你可以將要寫入的元素先寫入二維數組中然後將它整個賦值給對應Range的Value值
這樣就可以避免效率的問題
COM組件操作Excel的方式先總結到這~下回繼續補充~ 希望對需要的朋友有用~
注:本文章中涉及技術共享版權歸本人所有,如發現未經允許用作非法用作商業用途,將進行法律追究