實際C#項目中經常會涉及到需要對本地Excel文件進行操作,特別是一些包含數據記錄、分析、匯總功能模塊的項目。常用的操作Excel文件的方法主要有三個:
1. OleDb:
這種方式是把整個Excel文件當做一個數據源來進行數據的讀取操作。
優點:實現方式簡單,讀取速度快;
缺點:讀取Excel數據的過程不太靈活,對內存的占用比較高,當數據量變的很大時,容易由於內存空間不足導致內存溢出異常。(不過貌似對於今天電腦的硬件配置來說,內存問題不大)
2. Com組件
這種方式是通過Com組件 Microsoft.Office.Interop.Excel.dll實現Excel文件的操作。
優點:讀取Excel數據非常靈活,可以實現Excel具有的各種數據處理功能;
缺點:對數據的訪問時基於單元格方式實現的,所以讀寫數據較慢,特別是當數據量較大時,訪問效率問題更為突出。另一點是要求本機安裝了Microsoft Office組件。
3. NPOI
這種方式是通過NPOI庫實現Excel文件操作,可以在沒有安裝微軟Office的情況下使用。
優點:讀取Excel數據速度較快,操作方式靈活;
缺點:試了再說!
NPOI支持的文件格式處理xls、xlsx外,還包括doc、ppt、vsd等,功能強大,人稱Excel一哥。本文就准備單獨談一談NPOI對Excel的基本操作。
NPOI是什么?
NPOI的log圖標如下:
NPOI中N指代的是.Net,POI是一個完全開源的Java寫成的庫,能夠在沒有安裝微軟Office或者相應環境的情況下讀寫Excel、Word等微軟OLE2組件文檔,幾乎支持所有的Office97~Office2007的文件格式。所以NPOI就是POI項目的.Net版本。目前NPOI的最新版本是今年5月份發布的V2.2.1,包含了.Net Framework2和.Net Framework4兩個版本。
各個版本.Net Framework對應信息如下:
可以在C盤——C:\Windows\Microsoft.NET\Framework 下查看本機已經安裝的.Net Framework版本,在我的機器上安裝了以下版本:
NPOI庫下載、解壓
NPOI官網下載地址:點擊打開鏈接,打開之后,點擊紅色框里的“NPOI 2.2.1 package”即可下載:
下載完成的壓縮包大小只有3.5MB,解壓后可以看到主要文件其實就是5個Dll文件(.Net 2.0和.Net 4.0):
使用的時候只要在自己的C#項目中添加這幾個動態庫文件的引用就可以了。
在C#工程中添加NPOI動態庫引用
新建Visual Studio C# 控制台應用程序(或Windows窗體應用程序、WPF應用程序等均可),在解決方案管理器里項目下的“引用”上右擊“添加引用”:
在彈出的“引用管理器”對話框中單擊“瀏覽(B)”,選擇NPOI所在的文件夾,根據機器上.Net Framework版本,選擇Net20或Net40下的動態庫。
添加完成之后展開項目下的“引用”項,可以看到剛才所添加的動態庫。
經過簡單的“添加引用”之后就可以在自己的代碼中使用NPOI提供的接口實現各種Excel操作了。
Excel工作簿、工作表、xls、xlsx概念
在用NPOI編碼之前,簡單明確一下Excel中工作簿、工作表、xls、xlsx的概念,行、列、單元格等很明了的概念就不啰嗦了。
1. 每一個Excel文件都可以看做是一個工作簿,當打開一個Excel文件時,就等於打開了一個Excel工作簿。
2. 當打開了excel工作簿后在窗口底部看到的“Sheet”標簽標示的是工作表,有幾個標簽就表示有幾個工作表。
簡單做一個類比,一個Excel文件即一個工作簿可以看做一本書,一個工作表即一個Sheet頁面是書內的一頁,可以 有很多頁。Excel2003最多可以添加255(有強迫症的程序猿最愛的數字之一)個,Excel2007隨意加。
3. xls是Office 2003以及之前版本Excel的擴展名,xlsx是Office 2007及之后版本Excel所用的擴展名。xlsx用新的基於 XML的壓縮文件格式取代了之前的默認文件格式,在傳統的文件名后面添加了字面x(即.docx取代.doc、.xlsx取 代.xls,等等),使其占用的空間更小。xlsx向下兼容xls。
新建一個Excel工作表
除添加Dll文件的引用外,還需要添加名稱空間:
- using NPOI.SS.UserModel;
- using NPOI.HSSF.UserModel;
- using NPOI.XSSF.UserModel;
HSSF使用於2007之前的xls版本,XSSF適用於2007及其之后的xlsx版本。
以下程序新建一個Excel 2003 xls和一個2007 xlsx文件,跟用Office建立的標准Excel格式一樣,每一個Excel文件初始包含了3個工作表。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using NPOI.SS.UserModel;
- using NPOI.HSSF.UserModel;
- using NPOI.XSSF.UserModel;
- using System.IO;
- namespace Excel_NPOI
- {
- class Program
- {
- static void Main(string[] args)
- {
- HSSFWorkbook workbook2003 = new HSSFWorkbook(); //新建xls工作簿
- workbook2003.CreateSheet("Sheet1"); //新建3個Sheet工作表
- workbook2003.CreateSheet("Sheet2");
- workbook2003.CreateSheet("Sheet3");
- FileStream file2003 = new FileStream(@"E:\Excel2003.xls", FileMode.Create);
- workbook2003.Write(file2003);
- file2003.Close(); //關閉文件流
- workbook2003.Close();
- XSSFWorkbook workbook2007 = new XSSFWorkbook(); //新建xlsx工作簿
- workbook2007.CreateSheet("Sheet1");
- workbook2007.CreateSheet("Sheet2");
- workbook2007.CreateSheet("Sheet3");
- FileStream file2007 = new FileStream(@"E:\Excel2007.xlsx", FileMode.Create);
- workbook2007.Write(file2007);
- file2007.Close();
- workbook2007.Close();
- }
- }
- }
運行之后會在E盤根目錄下生成Excel2003.xls和Excel2007.xlsx兩個文件。
寫入Excel文件數據
以xls文件為例,介紹把數據寫入Excel文件的方法。
寫數據要遵循一定的順序,可以概括為:讀取(或新建一個工作簿)->獲取工作表->對工作表添加行->對每一行添加單元格->對單元格賦值;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using NPOI.SS.UserModel;
- using NPOI.HSSF.UserModel;
- using NPOI.XSSF.UserModel;
- using System.IO;
- namespace Excel_NPOI
- {
- class Program
- {
- static void Main(string[] args)
- {
- HSSFWorkbook workbook2003 = new HSSFWorkbook(); //新建工作簿
- workbook2003.CreateSheet("Sheet1"); //新建1個Sheet工作表
- HSSFSheet SheetOne = (HSSFSheet)workbook2003.GetSheet("Sheet1"); //獲取名稱為Sheet1的工作表
- //對工作表先添加行,下標從0開始
- for (int i = 0; i < 10; i++)
- {
- SheetOne.CreateRow(i); //創建10行
- }
- //對每一行創建10個單元格
- HSSFRow SheetRow = (HSSFRow)SheetOne.GetRow(0); //獲取Sheet1工作表的首行
- HSSFCell[] SheetCell = new HSSFCell[10];
- for (int i = 0; i < 10; i++)
- {
- SheetCell[i] = (HSSFCell)SheetRow.CreateCell(i); //為第一行創建10個單元格
- }
- //創建之后就可以賦值了
- SheetCell[0].SetCellValue(true); //賦值為bool型
- SheetCell[1].SetCellValue(0.000001); //賦值為浮點型
- SheetCell[2].SetCellValue("Excel2003"); //賦值為字符串
- SheetCell[3].SetCellValue("123456789987654321");//賦值為長字符串
- for (int i = 4; i < 10; i++)
- {
- SheetCell[i].SetCellValue(i); //循環賦值為整形
- }
- FileStream file2003 = new FileStream(@"E:\Excel2003.xls", FileMode.Create);
- workbook2003.Write(file2003);
- file2003.Close();
- workbook2003.Close();
- }
- }
- }
運行之后在生成的Exce2003.xls中的內容為:

讀取Excel文件數據
HSSFWorkbook類和XSSFWorkbook類都繼承自IWorkbook類,所以在不知道所要讀取的Excel文件時xls還是xlsx時,可以使用IWorkbook來聲明一個通用的工作簿變量,隨后根據傳入的文件名判斷是xls還是xlsx。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using NPOI.SS.UserModel;
- using NPOI.HSSF.UserModel;
- using NPOI.XSSF.UserModel;
- using System.IO;
- namespace Excel_NPOI
- {
- class Program
- {
- static void Main(string[] args)
- {
- IWorkbook workbook = null; //新建IWorkbook對象
- string fileName = "E:\\Excel2003.xls";
- FileStream fileStream = new FileStream(@"E:\Excel2003.xls", FileMode.Open, FileAccess.Read);
- if (fileName.IndexOf(".xlsx") > 0) // 2007版本
- {
- workbook = new XSSFWorkbook(fileStream); //xlsx數據讀入workbook
- }
- else if (fileName.IndexOf(".xls") > 0) // 2003版本
- {
- workbook = new HSSFWorkbook(fileStream); //xls數據讀入workbook
- }
- ISheet sheet = workbook.GetSheetAt(0); //獲取第一個工作表
- IRow row;// = sheet.GetRow(0); //新建當前工作表行數據
- for (int i = 0; i < sheet.LastRowNum; i++) //對工作表每一行
- {
- row = sheet.GetRow(i); //row讀入第i行數據
- if (row != null)
- {
- for (int j = 0; j < row.LastCellNum; j++) //對工作表每一列
- {
- string cellValue = row.GetCell(j).ToString(); //獲取i行j列數據
- Console.WriteLine(cellValue);
- }
- }
- }
- Console.ReadLine();
- fileStream.Close();
- workbook.Close();
- }
- }
- }
這段代碼實現讀取一個Excel文件內第一個工作表中的所有單元格內容,並打印輸出。
取在上段代碼中生成的xml文件作為輸入,運行結果為: