基于 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 建立一个最小化空白文档的方式。

 

相关文章
相关标签/搜索