基於 DocumentFormat.OpenXml 操做 Excel (1)-- 初識

  最近抽空研究了一下 基於DocumentFormat.OpenXml操做Excel,也把本身的理解記錄下來,便於往後能夠查閱。api

  各類系統中,導出Excel是一種很常見的功能,在C#/.Net 環境下, 市面上存在不少相關的類庫,開源免費的有基於JAVAPOI移植過來的 NPOIEPPlusOpenXML 等等;也有收費的 如 Aspose.CellsSpire.XLS 等。性能優化

  收費的商業組件在性能,功能上會通常來講都會比較好,例如Aspose.Cells,在性能上是比較卓越的,價格最便宜也要1000美金左右。 可是大部分公司,特別是初創公司,考慮到成本問題,用得比較多的,可能仍是會使用開源免費的 NPOIEPPlus,而OpenXML(DocumentFormat.OpenXml) 是微軟官方推出的一個操做Excel, Word, PPT文件的組件,並且操做的是更爲底層的部分,可以作到靈活和精確的控制,可是自己操做起來會比較複雜,有些順序的限制,會感受沒有 NPOI 和 EPPlus 方便,並且生成出來的excel搞很差還會提示錯誤(有可能WPS打開不會,office打開會),並且性能方面雖然操做底層,可是也要看使用者自己,不必定性能能夠很高。因此自己是比較少人會考慮使用它。工具

  這個組件爲啥叫 OpenXML SDK,由於從07版本以後,office系列的文檔,包括Excel, Word, PPT這些文檔,都是使用XML方式存儲的。 而 Office 的 Open XML 文件格式規範是一個開放的國際性標準 ,是 ECMA 376 標準, 能夠查閱這個網址:https://www.ecma-international.org/publications/standards/Ecma-376.htm 。 因此若是要學習這個SDK,則須要瞭解Excel裏面 XML的組成元素,這個能夠查閱 ECMA 376 標準的定義,可是會比較難啃。 可是瞭解Excel的內部組成,也對於你後期操做Excel的準確度,以及性能優化也是有幫助的。另外,因爲是操做XML, 因此 OpenXML SDK只能適用與07版本後的office, 像2003版本的Excel 文件(.xls)是不支持的。性能

  在一個文檔的內部,都是由多份XML的東西來組成的。 咱們能夠本身新建一個Excel文檔(.xlsx),而後修改其後綴名 xlsx 爲 rar/zip, 能夠直接解壓。學習

  以下圖所示:開發工具

   

 

  

  從以上的圖中解壓出來後的文件,能夠看出,一個 Excel (.xlsx)文件裏面包含不少個XML文件,分別表明一個Excel不一樣模塊的數據組成。優化

  從名字上,咱們大概初步能夠猜想出幾點: spa

  (1)workbook.xml 一個工做簿(Excel文件)的總覽3d

  (2)styles.xml 樣式相關excel

  (3)worksheets文件夾,包含多份xml, 每一份表明一個工做簿(Excel文件)裏面其中的一個工做表(WorkSheet)

  (4)theme 文件夾,Excel主題相關

  (5)printerSettings文件夾, 打印設置相關

 

那麼再來看看,初步經過代碼應該怎麼實現。

微軟官方提供的文檔說明,能夠查閱:https://docs.microsoft.com/zh-cn/office/open-xml/structure-of-a-spreadsheetml-document

OpenXML SDK 對應的Nuget包叫DocumentFormat.OpenXml,目前最新版本是 2.11.3,地址是: https://www.nuget.org/packages/DocumentFormat.OpenXml/   

OpenXML SDK 的相關類型說明,能夠查閱微軟官方提供的API文檔:https://docs.microsoft.com/zh-cn/dotnet/api/documentformat.openxml.spreadsheet.workbook?view=openxml-2.8.1

在C#.Net 項目中,經過VS開發工具的Nuget管理工具安裝,也能夠直接在終端經過nuget包管理命令安裝:  Install-Package DocumentFormat.OpenXml -Version 2.11.3 

 

 

根據微軟官方的文檔,先來經過C#代碼,簡單生成一個excel文件,而且保存到磁盤。 經過Nuget安裝好SDK。

根據微軟官方的介紹,一份最小(空白)工做簿必須包含如下內容,要:

    一、有一個工做表(WorkSheet)

    二、工做表的Id

    三、指向工做表定義位置的關係 Id 

 

可能聽起來有點難理解,經過這個來看下面的代碼示例(能夠運行的)  

 1 using System;
 2 using System.IO;
 3 using DocumentFormat.OpenXml;
 4 using DocumentFormat.OpenXml.Packaging;
 5 using DocumentFormat.OpenXml.Spreadsheet;
 6 
 7 namespace PracticePart1
 8 {
 9     public class Program
10     {
11         public static void Main(string[] args)
12         {
13             //當前運行時路徑
14             var directoryInfo = new DirectoryInfo(Directory.GetCurrentDirectory());
15             var fileName = $@"PracticePart1-{DateTime.Now:yyyyMMddHHmmss}.xlsx";
16 
17             //文件路徑,保存在運行時路徑下
18             var filepath = Path.Combine(directoryInfo.ToString(), fileName);
19             Console.WriteLine($"FilePath: {filepath}");
20 
21             //建立SpreadsheetDocument對象,xlsx類型,經過路徑
22             var spreadsheetDocument = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook);
23 
24             //經過Stream對象
25             //MemoryStream ms = new MemoryStream();
26             //SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook);
27 
28             //調用AddWorkbookPart, 建立WorkbookPart對象, 建立Workbook對象(至關於XML根元素)關聯到WorkbookPart
29             var workbookPart = spreadsheetDocument.AddWorkbookPart();
30             workbookPart.Workbook = new Workbook();
31 
32             //經過上面的WorkbookPart,建立WorksheetPart對象,建立Worksheet對象(至關於XML根元素)關聯到 WorksheetPart
33             var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
34             worksheetPart.Worksheet = new Worksheet(new SheetData());
35 
36             // 建立Sheets 到 Workbook
37             var sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());
38 
39             // 建立添加Sheet對象, Id關聯 Worksheet, 從而命名工做表的名稱
40             var sheet = new Sheet()
41             {
42                 Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
43                 SheetId = 1,
44                 Name = "myFirstSheet"
45             };
46 
47             //追加到 Sheets
48             sheets.Append(sheet);
49 
50             //保存到磁盤
51             workbookPart.Workbook.Save();
52 
53             // Close the document.
54             spreadsheetDocument.Close();
55         }
56     }
57 }

 

  以上是能夠直接運行,而後生成Excel文件。上述涉及到的幾個類型,依據我我的的理解,下面簡單說明下。

  SpreadsheetDocument 表格文檔類, 從字面意思,它就表示一個Excel相關的文檔包。 經過它的Create方法, 經過枚舉來指定文檔類型(*.xlsx, 能夠指定其它如*.xltx, *.xlsm等),同時指定文件路徑(重載方法中,是能夠支持傳入一個Stream),建立一個document對象。而後建立表示 工做簿 的WorkbookPart, 建立表示 工做表的 WorksheetPart, 這個時候符合上訴的 第一個要求【有一個工做表(WorkSheet)】。

  接着經過工做簿對象Workbook建立一個Sheets,表示工做簿中的全部表。 這裏要先明白Sheet Worksheet 的這2個的不一樣:

  (1)Worksheet : 表示的是工做簿的一份工做表的內容定義,就是咱們打開Excel文件,下方顯示sheet1, sheet2,sheet3....的每一份工做表。

  (2)Sheet : 表明的是工做簿的一個表,它能夠是工做表(Worksheet), 也能夠圖表(ChartSheet),也能夠是其它類型的表。它自己不涉及具體表怎麼定義,可是會經過Id關聯具體表的定義; 因此 Sheets 是表示工做簿中關聯的全部表的集合(圖表,工做表,宏表等)。 好比一個Sheets,它其中包含2個工做表,1個圖表,而具體的定義放在其它的地方,通常一個表的定義有一個xml。 

  Sheet 對象, 有一個 IdSheetId, 這2個字段。 按照上訴的 第二個要求 【工做表的Id】,就是指 SheetId, 本身賦值。 第三個要求【指向工做表定義位置的關係 Id 】, 就是指這個Id字段, 這個Id 指向工做表定義位置(就是指Sheet 關聯到具體哪一個 WorksheetPart ), 經過 WorkbookPart.GetIdOfPart 的方法來獲取這個Id

 

  以上就是DocumentFormat.OpenXml 建立一個最小化空白文檔的方式。

 

相關文章
相關標籤/搜索