Office Open XML学习(1)-创建excel文档,并向单元格中插入字符串

简介: 做企业级应用,跟office打交道是少不了的。这里的Office不仅仅局限于微软的Office,还有第三方的Open Office之类。.Net传统的Office操作方法(比如OleDB,OWC之类),有几大缺点: 一是不通用(仅能处理微软的Office,不能与其它非Windows平台交换数据),二是性能差(导出一个Excel,如果记录数上万条,速度很慢),三是服务器通常要安装Office Web Components(即OWC组件)。
做企业级应用,跟office打交道是少不了的。这里的Office不仅仅局限于微软的Office,还有第三方的Open Office之类。.Net传统的Office操作方法(比如OleDB,OWC之类),有几大缺点:
一是不通用(仅能处理微软的Office,不能与其它非Windows平台交换数据),
二是性能差(导出一个Excel,如果记录数上万条,速度很慢),
三是服务器通常要安装Office Web Components(即OWC组件)。

 

自从Open XML出现后,这种情况在很大程度上得到了改观,Open XML已经逐渐成为一种办公文档的通用国际标准了(该标准基于XML格式),详情见百度百科 http://baike.baidu.com/view/1201978.htm

 

要在C#中使用Open XML,需先下载Open XML SDK (目前最高版本为2.0),下载地址为: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=c6e744e5-36e9-45f5-8d8c-331df206e0d0

 

安装完以后,就能直接使用了,下面的代码演示了,如何创建一个Excel文档,并创建一个工作表"博客园",最后在该工作表的单元格A1中插入字符串
using System;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;


namespace ExcelSample
{
    class Program
    {
        static void Main(string[] args)
        {
            string excelFilePath = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "Sample.xlsx");

            using (SpreadsheetDocument excelDocument = CreateSpreadsheetDocument(excelFilePath))
            {
                //添加工作表(Sheet)-"博客园"
                WorksheetPart worksheetPart = InsertWorksheet(excelDocument.WorkbookPart,"博客园");

                //工作表插入单元格A1
                Cell cell = InsertCellInWorksheet("A", 1, worksheetPart);

                //创建多个工作表可共用的字符串容器
                SharedStringTablePart shareStringPart = CreateSharedStringTablePart(excelDocument.WorkbookPart);                

                //在共用字符串容器里插入一个字符串
                int strIndex = InsertSharedStringItem("菩提树下的杨过 http://www.cnblogs.com/yjmyzz", shareStringPart);

                //设置单元格的"值"
                cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
                cell.CellValue = new CellValue(strIndex.ToString());//注:这里要设置为目标字符串在SharedStringTablePart中的索引
               
                worksheetPart.Worksheet.Save();
            }

            Console.WriteLine("{0} 已经成功生成!", excelFilePath);

            Console.Read();
        }

        /// <summary>
        /// 创建一个SpreadsheetDocument对象
        /// </summary>
        /// <param name="excelFileName"></param>
        /// <returns></returns>
        static SpreadsheetDocument CreateSpreadsheetDocument(string excelFileName)
        {
            SpreadsheetDocument excel = SpreadsheetDocument.Create(excelFileName, SpreadsheetDocumentType.Workbook, true);
            WorkbookPart workbookpart = excel.AddWorkbookPart();
            workbookpart.Workbook = new Workbook();
            return excel;
        }

        /// <summary>
        /// 插入worksheet
        /// </summary>
        /// <param name="workbookPart"></param>
        /// <returns></returns>
        private static WorksheetPart InsertWorksheet(WorkbookPart workbookPart, string sheetName = null)
        {
            //创建一个新的WorkssheetPart(后面将用它来容纳具体的Sheet)
            WorksheetPart newWorksheetPart = workbookPart.AddNewPart<WorksheetPart>();
            newWorksheetPart.Worksheet = new Worksheet(new SheetData());
            newWorksheetPart.Worksheet.Save();

            //取得Sheet集合
            Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>();
            if (sheets == null)
            {
                sheets = workbookPart.Workbook.AppendChild<Sheets>(new Sheets());
            }

            string relationshipId = workbookPart.GetIdOfPart(newWorksheetPart);

            //得到Sheet的唯一序号
            uint sheetId = 1;
            if (sheets.Elements<Sheet>().Count() > 0)
            {
                sheetId = sheets.Elements<Sheet>().Select(s => s.SheetId.Value).Max() + 1;
            }

            string sheetTempName = "Sheet" + sheetId;

            if (sheetName != null)
            {
                bool hasSameName = false;
                //检测是否有重名
                foreach (var item in sheets.Elements<Sheet>())
                {
                    if (item.Name == sheetName)
                    {
                        hasSameName = true;
                        break;
                    }
                }
                if (!hasSameName)
                {
                    sheetTempName = sheetName;
                }
            }

            //创建Sheet实例并将它与sheets关联
            Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetTempName };
            sheets.Append(sheet);
            workbookPart.Workbook.Save();

            return newWorksheetPart;
        }

        /// <summary>
        /// 创建一个SharedStringTablePart(相当于各Sheet共用的存放字符串的容器)
        /// </summary>
        /// <param name="workbookPart"></param>
        /// <returns></returns>
        private static SharedStringTablePart CreateSharedStringTablePart(WorkbookPart workbookPart)
        {
            SharedStringTablePart shareStringPart = null;
            if (workbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
            {
                shareStringPart = workbookPart.GetPartsOfType<SharedStringTablePart>().First();
            }
            else
            {
                shareStringPart = workbookPart.AddNewPart<SharedStringTablePart>();
            }
            return shareStringPart;
        }

        /// <summary>
        /// 向工作表插入一个单元格
        /// </summary>
        /// <param name="columnName">列名称</param>
        /// <param name="rowIndex">行索引</param>
        /// <param name="worksheetPart"></param>
        /// <returns></returns>
        private static Cell InsertCellInWorksheet(string columnName, uint rowIndex, WorksheetPart worksheetPart)
        {
            Worksheet worksheet = worksheetPart.Worksheet;
            SheetData sheetData = worksheet.GetFirstChild<SheetData>();
            string cellReference = columnName + rowIndex;//列的引用字符串,类似:"A3"或"B5"

            //如果指定的行存在,则直接返回该行,否则插入新行
            Row row;
            if (sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
            {
                row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
            }
            else
            {
                row = new Row() { RowIndex = rowIndex };
                sheetData.Append(row);
            }

            //如果该行没有指定ColumnName的列,则插入新列,否则直接返回该列
            if (row.Elements<Cell>().Where(c => c.CellReference.Value == columnName + rowIndex).Count() > 0)
            {
                return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First();
            }
            else
            {
                //列必须按(字母)顺序插入,因此要先根据"列引用字符串"查找插入的位置
                Cell refCell = null;
                foreach (Cell cell in row.Elements<Cell>())
                {
                    if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
                    {
                        refCell = cell;
                        break;
                    }
                }

                Cell newCell = new Cell() { CellReference = cellReference };
                row.InsertBefore(newCell, refCell);

                worksheet.Save();
                return newCell;
            }
        }

        /// 向SharedStringTablePart添加字符串
        /// </summary>
        /// <param name="text">字符串内容</param>
        /// <param name="shareStringPart">sharedStringTablePart内容</param>
        /// <returns>如果要添加的字符串已经存在,则直接返回该字符串的索引</returns>
        private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
        {
            //检测SharedStringTable是否存在,如果不存在,则创建一个
            if (shareStringPart.SharedStringTable == null)
            {
                shareStringPart.SharedStringTable = new SharedStringTable();
            }

            int i = 0;

            //遍历SharedStringTable中所有的Elements,查看目标字符串是否存在
            foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>())
            {
                if (item.InnerText == text)
                {
                    return i;
                }
                i++;
            }

            //如果目标字符串不存在,则创建一个,同时把SharedStringTable的最后一个Elements的"索引+1"返回
            shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
            shareStringPart.SharedStringTable.Save();

            return i;
        }
    }
}
Sample.xlsx的打开截图:
下面这张图描述了Excel2007的大概结构:(摘自MSDN)
前面提到过Open XML是一个基于XML的标准,Open XML SDK安装后,提供了一个工具"Open XML SDK 2.0 Productivity Tool",可以用来查看所有支持Open XML标准的文档DOM结构
该工具还能将任何Open Document(即支持Open XML标准的office文档),直接生成相应的C#代码(很给力的一个功能!)
 
最后再给出微软的一些在线学习地址:
另外codeplex上还有一个利用openxml对excel/word常用操作进行封装的开源项目:http://simpleooxml.codeplex.com/
目录
相关文章
|
XML 数据采集 存储
使用Java和XPath在XML文档中精准定位数据
在数据驱动的时代,从复杂结构中精确提取信息至关重要。XML被广泛用于数据存储与传输,而XPath则能高效地在这些文档中导航和提取数据。本文深入探讨如何使用Java和XPath精准定位XML文档中的数据,并通过小红书的实际案例进行分析。首先介绍了XML及其挑战,接着阐述了XPath的优势。然后,提出从大型XML文档中自动提取特定产品信息的需求,并通过代理IP技术、设置Cookie和User-Agent以及多线程技术来解决实际网络环境下的数据抓取问题。最后,提供了一个Java示例代码,演示如何集成这些技术以高效地从XML源中抓取数据。
513 7
使用Java和XPath在XML文档中精准定位数据
|
XML 存储 JSON
Twaver-HTML5基础学习(19)数据容器(2)_数据序列化_XML、Json
本文介绍了Twaver HTML5中的数据序列化,包括XML和JSON格式的序列化与反序列化方法。文章通过示例代码展示了如何将DataBox中的数据序列化为XML和JSON字符串,以及如何从这些字符串中反序列化数据,重建DataBox中的对象。此外,还提到了用户自定义属性的序列化注册方法。
248 1
|
XML Java 数据格式
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
165 1
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的计算机office课程平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的计算机office课程平台的详细设计和实现(源码+lw+部署文档+讲解等)
191 5
|
JavaScript Java 测试技术
基于ssm+vue.js的计算机office课程平台附带文章和源代码设计说明文档ppt
基于ssm+vue.js的计算机office课程平台附带文章和源代码设计说明文档ppt
166 1
|
人工智能 文字识别 自然语言处理
1.6K star!这个开源文本提取神器,5分钟搞定PDF/图片/Office文档!
Kreuzberg 是一个基于 Python 的文本提取库,支持从 PDF、图像、Office 文档等 20+ 格式中提取文本内容。采用 MIT 开源协议,具备本地处理、异步架构、智能 OCR 等特性,特别适合需要隐私保护的文档处理场景。
1478 1
|
数据可视化 数据挖掘 大数据
1.1 学习Python操作Excel的必要性
学习Python操作Excel在当今数据驱动的商业环境中至关重要。Python能处理大规模数据集,突破Excel行数限制;提供丰富的库实现复杂数据分析和自动化任务,显著提高效率。掌握这项技能不仅能提升个人能力,还能为企业带来价值,减少人为错误,提高决策效率。推荐从基础语法、Excel操作库开始学习,逐步进阶到数据可视化和自动化报表系统。通过实际项目巩固知识,关注新技术,为职业发展奠定坚实基础。
|
XML 前端开发 Java
XML基本概念入门学习指南
XML(eXtensible Markup Language)是一种可扩展的标记语言,和HTML语言语法类似,同属于标记语言。
548 14
【Azure App Service】使用Microsoft.Office.Interop.Word来操作Word文档,部署到App Service后报错COMException
System.Runtime.InteropServices.COMException (0x80040154): Retrieving the COM class factory for component with CLSID {000209FF-0000-0000-C000-000000000046} failed due to the following error: 80040154 Class not registered (0x80040154 (REGDB_E_CLASSNOTREG)).
319 2
excel 百分位函数 学习
excel 百分位函数 学习
801 1

热门文章

最新文章

相关课程

更多