NPOI 函式庫(NPOI.dll)

来源:互联网 发布:python caffe 编辑:程序博客网 时间:2024/05/18 00:35

在 .NET 上的 POI:NPOI

拜 Apache 的 POI 專案之賜,Java 的開發人員可以輕鬆的存取 Excel 檔案,而反觀 .NET 陣營幾乎只能在 Excel 物件模型以及 Jet 資料庫引擎中打轉,對於 .NET 陣營本身的開發人員似乎也不太公平,所以有幾位佛心來的開發者另外開發可直接存取 Excel 的函式庫,或是將 Java 中好用的函式庫移植到 .NET 環境來,POI 專案就是一例,在 .NET 上被稱為 NPOI。

POI 專案本身是處理 Office 檔案的函式庫,包含 Word、Excel、PowerPoint、Outlook、Visio、Publisher 等檔案,這些檔案都有一個共通的特性,就是它們都是微軟發展的 OLE Compound Document(複合文件),以 OLE Structured Storage(結構化儲存)格式儲存在檔案中,OLE 規範(以及處理 OLE API 呼叫等)對一般的開發人員來說是有相當的難度,因此利用 Excel 本身的物件模型是最容易的一件事。但 POI 專案並沒有使用到 Excel 的任何東西,它直接深入 OLE Compound Document 格式內去存取資料,也可以直接控制到各種儲存格的資訊(顏色,儲存格格式與樣式等),並將它物件導向化,外部開發人員只需要利用 POI 提供的屬性就可以控制 Office 格式的檔案資料。

 

NOTE

OLE Compound Document 是一種檔案儲存的格式,它是植基在 OLE 結構化儲存(Structured Storage)的基礎上,可以在同一個檔案資料流中儲存多種資料格式,以 Excel 為例,它可以同時儲存試算表(Spreadsheet)、圖表(Chart)、樣式(Style)、圖片(Pictures)以及方程式(Equation)等不同型式的資料,這些不同型式的資料都是由一組獨立格式的 CLSID 識別,再由 CLSID 在檔案區段中找出不同的 CLSID 儲存區,再深入儲存區讀出資料流,即可取回指定的資料。


圖:OLE複合文件結構(來源:http://msdn.microsoft.com/en-us/library/dd942415(PROT.10).aspx)

 

如果讀者對 Excel 檔案的實際內容有興趣,可以在 NPOI 網站中下載 POIFS Explorer,並用它開啟 Excel 檔案,就可以看到 Excel 檔案的實際組成:


圖:POIFS Explorer

NPOI 函式庫

NPOI 函式庫可以在 http://npoi.codeplex.com 中下載,目前的版本為 1.2.1,有分為 .NET 1.1 與 .NET 2.0 以上版本兩種,支援主要的 POI 專案提供的功能,但專案中的範例程式碼都是以 Excel 為標的,原因應該是 Excel 在伺服器端的處理遠比 Word 和 PowerPoint 等文件要多太多了,故筆者在本篇文章也是以 Excel 檔案為主要說明的標的。

NPOI 函式庫檔案有七個,分別是:

  • NPOI.DLL:NPOI 核心函式庫。
  • NPOI.DDF.DLL:NPOI 繪圖區讀寫函式庫。
  • NPOI.HPSF.DLL:NPOI 文件摘要資訊讀寫函式庫。
  • NPOI.HSSF.DLL:NPOI Excel BIFF 檔案讀寫函式庫。
  • NPOI.Util.DLL:NPOI 工具函式庫。
  • NPOI.POIFS.DLL:NPOI OLE 格式存取函式庫。
  • ICSharpCode.SharpZipLib.DLL:檔案壓縮函式庫。

一般需要存取 Excel 97-2003 格式(.xls)的檔案時,需要使用 NPOI、NPOI.HSSF、NPOI.POIFS 與 NPOI.Util 函式庫,因此專案中要引用這四個 DLL,若要一併存取文件摘要資訊時,則也要引用 NPOI.HPSF.DLL 檔案,以取得必要的類別宣告。開發人員通常只要集中精神在 NPOI.HSSF.UserModel 命名空間即可,它包含了控制 Excel 資料的各式類別物件供開發人員取用。

例如下列的 ASP.NET 程式碼可以生成一個空白的 Excel 檔案,並且添加三個指定名稱的試算表:

[C#]
  1. HSSFWorkbook workbook = new HSSFWorkbook();
  2. MemoryStream ms = new MemoryStream();
  3.  
  4. // 新增試算表。
  5. workbook.CreateSheet("試算表 A");
  6. workbook.CreateSheet("試算表 B");
  7. workbook.CreateSheet("試算表 C");
  8.  
  9. workbook.Write(ms);
  10. Response.AddHeader("Content-Disposition"string.Format("attachment; filename=EmptyWorkbook.xls"));
  11. Response.BinaryWrite(ms.ToArray());
  12.  
  13. workbook = null;
  14. ms.Close();
  15. ms.Dispose();

其執行結果就有如一般的檔案下載般,不過它的資料卻是一個完整的 Excel 資料檔:

將它用 Excel 打開來看,可以看到它的內容確實是以指定的試算表名稱所建立:

再試一些程式,我們可以在裡面添加資料,例如下列的程式碼:

[C#]
  1. HSSFWorkbook workbook = new HSSFWorkbook();
  2. MemoryStream ms = new MemoryStream();
  3.  
  4. // 新增試算表。
  5. HSSFSheet sheet = workbook.CreateSheet("My Sheet");
  6. // 插入資料值。
  7. sheet.CreateRow(0).CreateCell(0).SetCellValue("0");
  8. sheet.CreateRow(1).CreateCell(0).SetCellValue("1");
  9. sheet.CreateRow(2).CreateCell(0).SetCellValue("2");
  10. sheet.CreateRow(3).CreateCell(0).SetCellValue("3");
  11. sheet.CreateRow(4).CreateCell(0).SetCellValue("4");
  12. sheet.CreateRow(5).CreateCell(0).SetCellValue("5");
  13.  
  14. workbook.Write(ms);
  15. Response.AddHeader("Content-Disposition"string.Format("attachment; filename=EmptyWorkbook.xls"));
  16. Response.BinaryWrite(ms.ToArray());
  17.  
  18. workbook = null;
  19. ms.Close();
  20. ms.Dispose();

將它下載下來,用 Excel 開啟,即可看到插入的資料值:

這樣還不夠,我們再設定一些東西,例如設定儲存格的背景色:

[C#]
  1. HSSFWorkbook workbook = new HSSFWorkbook();
  2. MemoryStream ms = new MemoryStream();
  3.  
  4. // 新增試算表。
  5. HSSFSheet sheet = workbook.CreateSheet("My Sheet");
  6. // 建立儲存格樣式。
  7. HSSFCellStyle style1 = workbook.CreateCellStyle();
  8. style1.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.BLUE.index2;
  9. style1.FillPattern = HSSFCellStyle.SOLID_FOREGROUND;
  10. HSSFCellStyle style2 = workbook.CreateCellStyle();
  11. style2.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.YELLOW.index2;
  12. style2.FillPattern = HSSFCellStyle.SOLID_FOREGROUND;
  13. // 設定儲存格樣式與資料。
  14. HSSFCell cell = sheet.CreateRow(0).CreateCell(0);
  15. cell.CellStyle = style1;
  16. cell.SetCellValue(0);
  17.  
  18. cell = sheet.CreateRow(1).CreateCell(0);
  19. cell.CellStyle = style2;
  20. cell.SetCellValue(1);
  21.  
  22. cell = sheet.CreateRow(2).CreateCell(0);
  23. cell.CellStyle = style1;
  24. cell.SetCellValue(2);
  25.  
  26. cell = sheet.CreateRow(3).CreateCell(0);
  27. cell.CellStyle = style2;
  28. cell.SetCellValue(3);
  29.  
  30. cell = sheet.CreateRow(4).CreateCell(0);
  31. cell.CellStyle = style1;
  32. cell.SetCellValue(4);
  33.  
  34. workbook.Write(ms);
  35. Response.AddHeader("Content-Disposition"string.Format("attachment; filename=EmptyWorkbook.xls"));
  36. Response.BinaryWrite(ms.ToArray());
  37.  
  38. workbook = null;
  39. ms.Close();
  40. ms.Dispose();

將它下載下來,用 Excel 開啟,即可看到設定樣式的試算表:

輸出沒有問題,那麼輸入呢?當然也沒有問題啦。例如目前手上有一個 Datas.xls 資料檔,它的內容是:

然後利用下列的程式碼:

[C#]
  1. if (this.fuUpload.HasFile)
  2. {
  3.     HSSFWorkbook workbook = new HSSFWorkbook(this.fuUpload.FileContent);
  4.     HSSFSheet sheet = workbook.GetSheetAt(0);
  5.  
  6.     DataTable table = new DataTable();
  7.  
  8.     HSSFRow headerRow = sheet.GetRow(0);
  9.     int cellCount = headerRow.LastCellNum;
  10.  
  11.     for (int i = headerRow.FirstCellNum; i < cellCount; i++)
  12.     {
  13.         DataColumn column = new DataColumn(headerRow.GetCell(i).StringCellValue);
  14.         table.Columns.Add(column);
  15.     }
  16.  
  17.     int rowCount = sheet.LastRowNum;
  18.  
  19.     for (int i = (sheet.FirstRowNum + 1); i < sheet.LastRowNum; i++)
  20.     {
  21.         HSSFRow row = sheet.GetRow(i);
  22.         DataRow dataRow = table.NewRow();
  23.  
  24.         for (int j = row.FirstCellNum; j < cellCount; j++)
  25.         {
  26.             if (row.GetCell(j) != null)
  27.                 dataRow[j] = row.GetCell(j).ToString();
  28.         }
  29.  
  30.         table.Rows.Add(dataRow);
  31.     }
  32.  
  33.     workbook = null;
  34.     sheet = null;
  35.  
  36.     this.gvExcel.DataSource = table;
  37.     this.gvExcel.DataBind();
  38. }

執行結果如下:

實例應用:將 DataTable 和 Excel 檔案間互轉

有了 NPOI 的支持,在伺服端將資料轉換成 Excel 檔案的功能將不再是大問題,也無須再使用匯出 HTML 表格的方式來模擬 Excel 檔案的暫行方案來解決,只要使用 NPOI 就可以得到正規的 Excel 資料檔,筆者也特別撰寫了一個簡單的由 DataTable 物件自動轉成 Excel 資料檔的小程式供讀者自行取用。

[C#]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Web;
  7. using NPOI;
  8. using NPOI.HPSF;
  9. using NPOI.HSSF;
  10. using NPOI.HSSF.UserModel;
  11. using NPOI.POIFS;
  12. using NPOI.Util;
  13.  
  14. public class DataTableRenderToExcel 
  15. {
  16.     public static Stream RenderDataTableToExcel(DataTable SourceTable)
  17.     {
  18.         HSSFWorkbook workbook = new HSSFWorkbook();
  19.         MemoryStream ms = new MemoryStream();
  20.         HSSFSheet sheet = workbook.CreateSheet();
  21.         HSSFRow headerRow = sheet.CreateRow(0);
  22.  
  23.         // handling header.
  24.         foreach (DataColumn column in SourceTable.Columns)
  25.             headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
  26.  
  27.         // handling value.
  28.         int rowIndex = 1;
  29.  
  30.         foreach (DataRow row in SourceTable.Rows)
  31.         {
  32.             HSSFRow dataRow = sheet.CreateRow(rowIndex);
  33.  
  34.             foreach (DataColumn column in SourceTable.Columns)
  35.             {
  36.           dataRow.CreateCell(column.Ordinal).SetCellValue(row[column].ToString());
  37.             }
  38.  
  39.             rowIndex++;
  40.         }
  41.  
  42.         workbook.Write(ms);
  43.         ms.Flush();
  44.         ms.Position = 0;
  45.  
  46.         sheet = null;
  47.         headerRow = null;
  48.         workbook = null;
  49.  
  50.         return ms;
  51.     }
  52.  
  53.     public static void RenderDataTableToExcel(DataTable SourceTable, string FileName)
  54.     {
  55.         MemoryStream ms = RenderDataTableToExcel(SourceTable) as MemoryStream;
  56.         FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write);
  57.         byte[] data = ms.ToArray();
  58.  
  59.         fs.Write(data, 0, data.Length);
  60.         fs.Flush();
  61.         fs.Close();
  62.  
  63.         data = null;
  64.         ms = null;
  65.         fs = null;
  66.     }
  67.  
  68.     public static DataTable RenderDataTableFromExcel(Stream ExcelFileStream, string SheetName, int HeaderRowIndex)
  69.     {
  70.         HSSFWorkbook workbook = new HSSFWorkbook(ExcelFileStream);
  71.         HSSFSheet sheet = workbook.GetSheet(SheetName);
  72.  
  73.         DataTable table = new DataTable();
  74.  
  75.         HSSFRow headerRow = sheet.GetRow(HeaderRowIndex);
  76.         int cellCount = headerRow.LastCellNum;
  77.  
  78.         for (int i = headerRow.FirstCellNum; i < cellCount; i++)
  79.         {
  80.             DataColumn column = new DataColumn(headerRow.GetCell(i).StringCellValue);
  81.             table.Columns.Add(column);
  82.         }
  83.  
  84.         int rowCount = sheet.LastRowNum;
  85.  
  86.         for (int i = (sheet.FirstRowNum + 1); i < sheet.LastRowNum; i++)
  87.         {
  88.             HSSFRow row = sheet.GetRow(i);
  89.             DataRow dataRow = table.NewRow();
  90.  
  91.             for (int j = row.FirstCellNum; j < cellCount; j++)
  92.                 dataRow[j] = row.GetCell(j).ToString();
  93.         }
  94.  
  95.         ExcelFileStream.Close();
  96.         workbook = null;
  97.         sheet = null;
  98.         return table;
  99.     }
  100.  
  101.     public static DataTable RenderDataTableFromExcel(Stream ExcelFileStream, int SheetIndex, int HeaderRowIndex)
  102.     {
  103.         HSSFWorkbook workbook = new HSSFWorkbook(ExcelFileStream);
  104.         HSSFSheet sheet = workbook.GetSheetAt(SheetIndex);
  105.  
  106.         DataTable table = new DataTable();
  107.  
  108.         HSSFRow headerRow = sheet.GetRow(HeaderRowIndex);
  109.         int cellCount = headerRow.LastCellNum;
  110.  
  111.         for (int i = headerRow.FirstCellNum; i < cellCount; i++)
  112.         {
  113.             DataColumn column = new DataColumn(headerRow.GetCell(i).StringCellValue);
  114.             table.Columns.Add(column);
  115.         }
  116.  
  117.         int rowCount = sheet.LastRowNum;
  118.  
  119.         for (int i = (sheet.FirstRowNum + 1); i < sheet.LastRowNum; i++)
  120.         {
  121.             HSSFRow row = sheet.GetRow(i);
  122.             DataRow dataRow = table.NewRow();
  123.  
  124.             for (int j = row.FirstCellNum; j < cellCount; j++)
  125.             {
  126.                 if (row.GetCell(j) != null)
  127.                     dataRow[j] = row.GetCell(j).ToString();
  128.             }
  129.  
  130.             table.Rows.Add(dataRow);
  131.         }
  132.  
  133.         ExcelFileStream.Close();
  134.         workbook = null;
  135.         sheet = null;
  136.         return table;
  137.     }
  138. }

它的呼叫方法很簡單,若是要將 DataTable 輸出到 Excel 檔案,只要將 DataTable 丟給 RenderDataTableToExcel() 方法即可。

[C#]
  1. DataTable table = new DataTable();
  2.  
  3. // 填充資料(由讀者自行撰寫)
  4.  
  5. // 產生 Excel 資料流。
  6. MemoryStream ms = DataTableRenderToExcel.RenderDataTableToExcel(table) as MemoryStream;
  7. // 設定強制下載標頭。
  8. Response.AddHeader("Content-Disposition"string.Format("attachment; filename=Download.xls"));
  9. // 輸出檔案。
  10. Response.BinaryWrite(ms.ToArray());
  11.  
  12. ms.Close();
  13. ms.Dispose();

若是要讀取 Excel 檔案並存到 DataTable,只要設定上傳的 Excel 檔案資料流、試算表索引(或名稱)以及起始列索引值即可:

[C#]
  1. if (this.fuUpload.HasFile)
  2. {
  3.     // 讀取 Excel 資料流並轉換成 DataTable。
  4.     DataTable table = DataTableRenderToExcel.RenderDataTableFromExcel(this.fuUpload.FileContent, 10);
  5.     this.gvExcel.DataSource = table;
  6.     this.gvExcel.DataBind();
  7. }

結語

NPOI 是一個好用又簡單的函式庫,可以幫助開發人員解決長久以來在伺服端的 Excel 檔案產生與存取的問題,它還有很多特別的功能可以利用(像是讀寫摘要資料),正等著讀者發掘它呢。

 

原创粉丝点击