Excel文档处理之Open XML

来源:互联网 发布:mac 截图 任意区域 编辑:程序博客网 时间:2024/05/22 12:11

引言

在使用Open XML处理Excel文档之前,需要先确定它的作用范围,Open XML适用于2007版本及以上的Excel文档的处理。

第二步就是配置Open XML的开发环境:Open XML相关下载链接。

1、新建Excel文档

咱们先从一个实际的Excel文档入手,在桌面上新建一个Excel文档,默认会有一个Sheet,可以理解为一个工作表或一个页面。

   

创建一个Excel所等价的代码如下:

//本代码段为简化代码,只作理解之用。//SpreadsheetDocument:Excel文档的变量类型//以path中所指定的地址和名称创建一个Excel文档//SpreadsheetDocumentType.Workbook:指明创建的文件类型为后缀名为.xlsx的Excel文档SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(path, SpreadsheetDocumentType.Workbook);
将刚刚新建的Excel文档的后缀名改为rar(压缩包格式),然后打开压缩包,看到如下图所示的目录,其中xl文件夹中的文件很重要,需要仔细研究。打开xl文件夹。

先打开workbook.xml,默认会用浏览器显示其内容,workbook.xml主要对sheet(理解为工作表或页面)进行宏观性全局性的描述。下图中,第二行开始到结束,由叫做“workbook”的元素包裹在最外层,可以把workbook理解为工作薄,但不完全等价于Excel文件。红色方框框起来的元素为“ sheets”,它的内部描述了该文档有几个sheet(理解为工作表或页面)。由于新建的Excel文档默认只有一个sheet,所以“sheets”元素的内部只有一个“sheet”元素,对应着创建Excel文档后默认的“Sheet1”工作表,图中的sheet元素内部,有三个必备属性:r:id、sheetId、name。r:id是字符串类型的属性,以“rId”+数字作为其内容;sheetId为数字类型的属性;name就是该sheet的名字。前两个属性都属于sheet的id值,都是隐含的内在的属性,name属性是外在的显露出来的属性,图中name属性的值“Sheet1”刚好对应新建的Excel中的默认的sheet名称。

2、添加一个sheet工作表

倘若在Excel中添加一个工作表,并将其命名为“测试”,会有什么变化呢?具体的操作要么把Excel文件后缀名恢复原样,要么可以再新建一个Excel,并添加一个工作表。再次打开workbook.xml文件时,会发现多了一个sheet元素。该sheet元素对应的r:id和sheetId的值都比默认的sheet元素的值增加了1,name属性的值为“测试”。

添加一个工作表等价的代码如下:

//本代码段为简化代码,只作理解之用。//workbookPart:管理Workbook工作薄//WorksheetPart:管理工作表,一个WorksheetPart对应一个工作表//workbookPart.AddNewPart<WorksheetPart>():添加一个新的WorksheetPartWorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();//workbookPart.Workbook.Sheets:Workbook元素中的Sheets元素//Sheets.Elements<Sheet>():Sheets元素中Sheet元素的集合//Elements<Sheet>().LastOrDefault():Sheet元素集合中最后一个Sheet元素或默认的Sheet元素Sheet sheet = workbookPart.Workbook.Sheets.Elements<Sheet>().LastOrDefault();//定义默认的sheetId值//当工作薄中一个工作表也没有时,便以1作为新添加的工作表的Sheet元素的Id值//当工作薄中存在工作表时,便将最后一个工作表的Id值加1作为新添加的工作表的Sheet元素的Id值UInt32Value sheetId = 1;if (sheet != null){    sheetId = sheet.SheetId + 1;}//AppendChild:添加一个子元素workbookPart.Workbook.Sheets.AppendChild(new Sheet(){    //Id为字符串类型的Id属性    Id = workbookPart.GetIdOfPart(worksheetPart),    //SheetId为数值类型的Id属性    SheetId = sheetId,    //工作表的名称    Name = sheetName});

3、向sheet工作表中添加内容

在上方压缩包目录图中,打开worksheets文件夹。该目录下有一个名为“sheet1.xml"的文件,对应默认的”Sheet1“工作表。有多少个工作表,这个文件夹里面就有多少个sheet文件,sheet文件对所有非空表格的信息都进行了登记。

打开sheet1.xml文件,内容如下图所示。其中sheetViews元素可以描述当前选中的表格所在的位置,由于新建的Excel文档没有选中表格,所有sheetViews没有描述;sheetData元素记录非空表格的位置及表格内容,同样,由于Excel没有写入任何内容,sheetData中也就没有记录。

这时,对空白的Sheet1工作表添加如下图所示的内容。分别在A1、B2、C3单元格添加了“1”、“数据”、“Data”,并选中B1单元格。添加这些数据后,sheet1.xml文件主要的变化如下图。sheetViews元素中,selection元素描述选中的单元格为B1。sheetData元素中,有三个row元素,分别对应添加的“1”、“数据”、“Data”;在row元素中,r属性表示第几行,c元素记录非空表格的位置及表格内容;在c元素中,r元素表示单元格的位置,其中第一个c元素中,v元素表示单元格的内容,第二个和第三个c元素的解释请看下面的内容。

在xl文件夹中,多了一个名为sharedStrings.xml的文件,这个文件名字面上的意思是共享字符串,这是Excel中很有意思的一个东西,它将可能会重复用到的字符串都存储于这个文件中。打开它,内容如下图所示,si元素中存储着可能会重复用到的字符串,可以想象,当N个单元格中的内容都是“数据”时,那么Excel就不用为每个单元格分配额外的存储空间,而只需要在上图中的v元素中存储该字符串的引用即可,例:在下图中,数据在sharedStrings.xml文件中的位置是第0个(默认从第0个开始),上图中c元素中t属性赋值为“s”,表明该单元格的内容为共享字符串,v元素中的值为0,表示该单元格中的内容为sharedStrings.xml文件中第0个字符串。

向表格中添加内容的代码如下:

//本代码段为简化代码,只作理解之用。//SheetData:记录非空单元格的位置及内容//worksheetPart:管理工作表,一个WorksheetPart对应一个工作表SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault();//Row:工作表中的行Row row = sheetData.Elements<Row>().LastOrDefault();//添加普通数据void AddData(object data){    Cell cell = row.AppendChild(new Cell()    {        //CellValue:单元格内容        CellValue = new CellValue() { Text = data.ToString() },        //DataType:单元格类型        DataType = CellValues.String,    });}//添加共享字符串private void AddSharedString(object data){    Cell cell = row.AppendChild(new Cell()    {        CellValue = new CellValue(Convert.ToString(GetSharedStringItemIndex(data.ToString()))),        DataType = CellValues.SharedString,    });}//获取指定字符串在SharedStringTable中的索引值,不存在就创建int GetSharedStringItemIndex(string value){    //字符串从0开始标记    int index = 0;    //寻找是否有与value相同的字符串,若有,则将index设置为对应的标记值,并返回    //SharedStringItem:共享字符串的数据类型    //sharedStringTable:共享字符串表    foreach (SharedStringItem item in sharedStringTable.Elements<SharedStringItem>())    {        if (item.InnerText == value)        {            return index;        }        index++;    }    //若没有与value相同的字符串,则添加一个字符串到共享字符串表中,并将其内容设置为value    sharedStringTable.AppendChild(new SharedStringItem(new Text(value)));    return index;}

4、表格样式

在xl文件夹中有一个styles.xml文件,这个文件保存着单元格的格式,包含背景、边框、字体等设置。在刚刚新建的Excel文档中,styles.xml中主要内容如下列图所示。fonts: 以font元素为单位存储字体样式;fills:以fill元素为单位存储填充样式;borders:以border元素为单位存储边框样式。以上每个元素都有一个相同的属性count,用于表示该元素包含几个子元素。在font元素中,sz:字体大小;color:字体颜色;name:字体类型。在fill元素中,patternFill:填充样式。在border元素中,left、right、top、bottom分别表示左右上下边框的样式。

cellXfs:以xf为单位存储表格样式,此处存储的表格样式是对font元素、fill元素、border元素的调用和组合。在xf元素中,将第0个border元素、第0个fill元素和第0个font元素组合成一个表格样式。在n个表格样式中,往往会有相同的字体样式、填充样式、边框样式,因此使用引用的方式设置表格样式可以节约存储空间。再者,在常规的Excel文档中,往往一大堆内容使用同一个表格样式,使用引用的方式调用表格样式可以节省大量存储空间。

倘若将第二行第二列的“数据”的单元格填充颜色设置为黄色,字体颜色设置为红色,worksheets文件夹中的sheet1.xml将会发生如下图所示的主要变化,在第二个row元素(即r 属性的值为2的row元素)中,位置为B2的c元素的s属性(单元格样式style)的值为1,表示该单元格的单元格样式引用上图中cellXfs元素中的第1个xf元素(上图中只有第0 个 xf元素)。

       

上方填充颜色和字体颜色的设置导致xl文件夹中styles.xml也发生了相应的变化,如下列三张图所示。多了一个font元素,该元素中,color属性的值“FFFF0000”代表红色,意为字体颜色为红色;多了一个fill元素,该元素中,fgColor的值“FFFFFF00”代表黄色,以为填充颜色为黄色;cellXfs元素中多了一个xf元素,fontId值为“2”,fontId值为“2”,即引用下方第一张图中的font和第二张图中的fill,并组合成一个单元格样式,供上图中红色方框内的s属性调用。



上述添加单元格样式的代码如下:

//本代码段为简化代码,只作理解之用。//Stylesheet:单元格样式Stylesheet stylesheet = workbookPart.WorkbookStylesPart.Stylesheet;//添加一个填充样式Fill fill = stylesheet.Fills.AppendChild(new Fill(){    PatternFill = new PatternFill()    {        PatternType = PatternValues.Solid,        ForegroundColor = new ForegroundColor()        {            Rgb = new HexBinaryValue((Color.Yellow).ToArgb().ToString("X"))        }    }});//添加一个字体样式Font font = stylesheet.Fonts.AppendChild(new Font(){      Color = new Color()      {            Rgb=new HexBinaryValue((Color.Red).ToArgb().ToString("X"))      }});//添加一个单元格样式stylesheet.CellFormats.AppendChild(new CellFormat(){      //引用上方定义的fill    FillId = (uint)fill.Index,      //引用上方定义的font      FontId = (uint)font.Index});

5、代码

代码分为两个部分:OXExcel类:Excel文档结构层次的节点或元素的处理;OXSheet:工作表内容层次的节点或元素的处理。

注:本代码段是本人经多次试验后的结果,但依然不尽如人意,主要表现在两个方面:1、表格样式部分只编写了修改背景颜色的功能;2、超链接的添加会导致一个后遗症,打开Excel文档后不修改任何东西,关闭时总会有一个是否保存的提示。

using System;using System.Linq;using System.Runtime.InteropServices;using DocumentFormat.OpenXml;using DocumentFormat.OpenXml.Packaging;using DocumentFormat.OpenXml.Spreadsheet;using System.IO;namespace OpenXMLDemo{    public class OXExcel    {        //判断文件是否只读的相关定义        [DllImport("kernel32.dll")]        public static extern IntPtr _lopen(string lpPathName, int iReadWrite);        [DllImport("kernel32.dll")]        public static extern bool CloseHandle(IntPtr hObject);        public const int OF_READWRITE = 2;        public const int OF_SHARE_DENY_NONE = 0x40;        public static IntPtr HFILE_ERROR = new IntPtr(-1);        //OpenXml中涉及Excel的元素,定义全局变量,方便长时间读写Excel文档        //SpreadsheetDocument:Excel文档的变量类型        private SpreadsheetDocument spreadsheetDocument = null;        //WorkbookPart:Excel文档的总管        private WorkbookPart workbookPart = null;        //表格格式总管        private Stylesheet stylesheet = null;        //文件路径+名字        private string path;        //程序运行时,打开通过文件流载入的Excel文件会提示只读        private FileStream fileStream;        //指定Excel的路径(包含名称)        public OXExcel(string path)        {            this.path = path;        }        //载入Excel        public bool LoadExcel()        {            //Excel是否存在            if (System.IO.File.Exists(path))            {                //Excel是否只读                if (!IsReadOnly())                {                    //使用文件流载入Excel,使得程序运行时,使用本程序外的软件打开Excel时,将会提示Excel只读,不能编辑。                    //可以防止在程序外部打开Excel,导致本程序失去对Excel的载入,从而程序崩溃、异常。                    fileStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);                    //OpenSettings:Excel打开后的设置                    OpenSettings openSettings = new OpenSettings();                    //设置Excel不自动保存                    openSettings.AutoSave = false;                    spreadsheetDocument = SpreadsheetDocument.Open(fileStream, true, openSettings);                    workbookPart = spreadsheetDocument.WorkbookPart;                    //下列子元素若不存在,则需要重新创建Excel                    if (workbookPart == null || workbookPart.Workbook == null || workbookPart.Workbook.Sheets == null ||                        workbookPart.SharedStringTablePart == null || workbookPart.SharedStringTablePart.SharedStringTable == null ||                        workbookPart.WorkbookStylesPart == null || workbookPart.WorkbookStylesPart.Stylesheet == null)                    {                        createExcel();                    }                    stylesheet = workbookPart.WorkbookStylesPart.Stylesheet;                }                else                {                    //只读                    return false;                }            }            else            {                createExcel();            }            return true;        }        //判断指定路径的Excel是否只读        private bool IsReadOnly()        {            IntPtr vHandle = _lopen(path, OF_READWRITE | OF_SHARE_DENY_NONE);            if (vHandle == HFILE_ERROR)            {                CloseHandle(vHandle);                return true;            }            CloseHandle(vHandle);            return false;        }        //创建Excel        private void createExcel()        {            //SpreadsheetDocument            if (spreadsheetDocument == null)            {                //以path中所指定的地址和名称创建一个Excel文档                //SpreadsheetDocumentType.Workbook:指明创建的文件类型为后缀名为.xlsx的Excel文档                spreadsheetDocument = SpreadsheetDocument.Create(path, SpreadsheetDocumentType.Workbook);            }            //WorkbookPart            workbookPart = spreadsheetDocument.WorkbookPart;            if (workbookPart == null)            {                workbookPart = spreadsheetDocument.AddWorkbookPart();            }            //Workbook            if (workbookPart.Workbook == null)            {                workbookPart.Workbook = new Workbook();            }            //Sheets            if (workbookPart.Workbook.Sheets == null)            {                workbookPart.Workbook.Sheets = new Sheets();            }            //SharedStringTablePart            if (workbookPart.SharedStringTablePart == null)            {                workbookPart.AddNewPart<SharedStringTablePart>();            }            //SharedStringTabel            if (workbookPart.SharedStringTablePart.SharedStringTable == null)            {                workbookPart.SharedStringTablePart.SharedStringTable = new SharedStringTable();            }            workbookPart.SharedStringTablePart.SharedStringTable.Save();            //WorkbookStylesPart            if (workbookPart.WorkbookStylesPart == null)            {                workbookPart.AddNewPart<WorkbookStylesPart>();            }            //Stylesheet            if (workbookPart.WorkbookStylesPart.Stylesheet == null)            {                workbookPart.WorkbookStylesPart.Stylesheet = new Stylesheet();            }            workbookPart.Workbook.Save();            //经过我的大量实践,在创建Workbook和Worksheet后,均需调用spreadsheetDocument.Dispose()方法,否则Excel文件会有问题            //但是Dispose()后,所有资源均释放了,所以需要重新载入Excel            //也许有人会想,为什么不在所有关于Excel的操作(包括创建、读写)完成后,再调用Dispose()?            //我的回答是:程序总会出现异常,异常时,并不会自动调用Dispose            //请原谅我的强迫症,1、为了能在程序运行时,保持对Excel的载入。2、遇到程序异常时,Excel文件不会出现任何问题。            reLoad();        }        //释放定义的全局变量等所有资源,并重新载入Excel        private void reLoad()        {            Dispose();            LoadExcel();        }        //判断Worksheet是否存在        public bool IsWorksheetExist(string sheetName)        {            //workbookPart:管理Workbook工作薄            //workbookPart.Workbook.Sheets:Workbook元素中的Sheets元素            //Sheets.Elements<Sheet>():Sheets元素中Sheet元素的集合            //Elements<Sheet>().FirstOrDefault():Sheet元素集合中第一个Sheet元素或默认的Sheet元素            //FirstOrDefault(s => s != null && s.Name != null && s.Name == sheetName)等同于如下代码            //foreach(Sheet s in workbookPart.Workbook.Sheets.Elements<Sheet>())            //{            //    寻找Name与sheetName相同的Sheet元素            //    if(s! = null && s.Name != null && s.Name == sheetName)            //    {            //       sheet = s;            //       break;            //    }            //}            //Sheet是工作表在宏观上的元素,它存储工作表的标识和名称            Sheet sheet = workbookPart.Workbook.Sheets.Elements<Sheet>().                FirstOrDefault(s => s != null && s.Name != null && s.Name == sheetName);            if (sheet == null)            {                return false;            }            //WorksheetPart:管理工作表,一个WorksheetPart对应一个工作表            //Worksheet是工作表在微观上的元素,它主要存储工作表中非空表格的内容            WorksheetPart worksheetPart = (WorksheetPart)workbookPart.GetPartById(sheet.Id);            //Worksheet,SheetData            if (worksheetPart.Worksheet == null || worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault() == null)            {                return false;            }            return true;        }        //添加一个工作表        public void AddWorksheetPart(string sheetName)        {            Sheet sheet = workbookPart.Workbook.Sheets.Elements<Sheet>().                FirstOrDefault(s => s != null && s.Name != null && s.Name == sheetName);            WorksheetPart worksheetPart = null;            if (sheet != null)            {                worksheetPart = (WorksheetPart)workbookPart.GetPartById(sheet.Id);            }            else            {                worksheetPart = workbookPart.AddNewPart<WorksheetPart>();            }            //Worksheet            if (worksheetPart.Worksheet == null)            {                worksheetPart.Worksheet = new Worksheet();            }            //SheetData            if (worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault() == null)            {                //workbookPart.AddNewPart<WorksheetPart>():添加一个新的WorksheetPart                worksheetPart.Worksheet.AppendChild(new SheetData());            }            worksheetPart.Worksheet.Save();            //Sheet            if (sheet == null)            {                sheet = workbookPart.Workbook.Sheets.Elements<Sheet>().LastOrDefault();                //定义默认的sheetId值,当工作薄中一个工作表也没有时,便以1作为新添加的Sheet元素的Id值                UInt32Value sheetId = 1;                if (sheet != null)                {                    sheetId = sheet.SheetId + 1;                }                //AppendChild:添加一个子元素                workbookPart.Workbook.Sheets.AppendChild(new Sheet()                {                    //Id为字符串类型的Id属性                    Id = workbookPart.GetIdOfPart(worksheetPart),                    //SheetId为数值类型的Id属性                    SheetId = sheetId,                    //工作表的名称                    Name = sheetName                });            }            workbookPart.Workbook.Save();            //此处解释同上方CreateExcel()方法中一致            reLoad();        }        //获取工作表        public WorksheetPart GetWorksheetPart(string sheetName)        {            //WorksheetPart            Sheet sheet = workbookPart.Workbook.Sheets.Elements<Sheet>().FirstOrDefault(s => s != null && s.Name != null && s.Name == sheetName);            WorksheetPart worksheetPart = null;            if (sheet != null)            {                worksheetPart = (WorksheetPart)workbookPart.GetPartById(sheet.Id);            }            else            {                return null;            }            //Worksheet,SheetData            if (worksheetPart.Worksheet == null || worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault() == null)            {                return null;            }            return worksheetPart;        }        //获取共享字符串表        public SharedStringTable GetSharedStringTable()        {            return workbookPart.SharedStringTablePart.SharedStringTable;        }        //根据背景颜色获取自定义的表格样式的索引,不存在则创建        public int GetStyleIndexByBackColor(System.Drawing.Color color)        {            checkStylesheet();            int fillIndex = getFillIndex(color);            int index = 0;            foreach (CellFormat cellFormat in stylesheet.CellFormats.Elements<CellFormat>())            {                if (cellFormat != null && cellFormat.FillId != null && cellFormat.FillId == fillIndex                    && cellFormat.FontId == null && cellFormat.BorderId == null)                {                    return index;                }                index++;            }            stylesheet.CellFormats.AppendChild(new CellFormat()            {                FillId = (uint)fillIndex,            });            stylesheet.Save();            return index;        }        //检验Stylesheet的完整性        private void checkStylesheet()        {            if (stylesheet.Fonts == null)            {                stylesheet.Fonts = new Fonts();            }            if (stylesheet.Fonts.ChildElements.Count == 0)            {                stylesheet.Fonts.AppendChild(new Font());            }            if (stylesheet.Fills == null)            {                stylesheet.Fills = new Fills();            }            if (stylesheet.Fills.ChildElements.Count == 0)            {                stylesheet.Fills.AppendChild(new Fill()                {                    PatternFill = new PatternFill()                    {                        PatternType = PatternValues.None                    }                });                stylesheet.Fills.AppendChild(new Fill()                {                    PatternFill = new PatternFill()                    {                        PatternType = PatternValues.Gray125                    }                });            }            if (stylesheet.Borders == null)            {                stylesheet.Borders = new Borders();            }            if (stylesheet.Borders.ChildElements.Count == 0)            {                stylesheet.Borders.AppendChild(new Border());            }            if (stylesheet.CellFormats == null)            {                stylesheet.CellFormats = new CellFormats();                if (stylesheet.CellFormats.ChildElements.Count == 0)                {                    stylesheet.CellFormats.AppendChild(new CellFormat());                }            }            stylesheet.Save();        }        //根据背景颜色获取Stylesheet的子元素Fill的索引值,不存在则创建        private int getFillIndex(System.Drawing.Color color)        {            int fillIndex = 0;            foreach (Fill fill in stylesheet.Fills.Elements<Fill>())            {                if (fill != null && fill.PatternFill != null && fill.PatternFill.PatternType != null &&                    fill.PatternFill.PatternType == PatternValues.Solid && fill.PatternFill.ForegroundColor != null &&                    fill.PatternFill.ForegroundColor.Rgb != null && fill.PatternFill.ForegroundColor.Rgb.Value != null &&                    fill.PatternFill.ForegroundColor.Rgb.Value == color.ToArgb().ToString("X"))                {                    return fillIndex;                }                fillIndex++;            }            stylesheet.Fills.AppendChild(new Fill()            {                PatternFill = new PatternFill()                {                    PatternType = PatternValues.Solid,                    ForegroundColor = new ForegroundColor()                    {                        Rgb = new HexBinaryValue(color.ToArgb().ToString("X"))                    }                }            });            stylesheet.Save();            return fillIndex;        }        // 释放所有资源        public void Dispose()        {            if (stylesheet != null)            {                stylesheet.Save();                stylesheet = null;            }            if (workbookPart != null)            {                workbookPart.Workbook.Save();                workbookPart = null;            }            if (spreadsheetDocument != null)            {                spreadsheetDocument.Close();                spreadsheetDocument.Dispose();                spreadsheetDocument = null;            }            if (fileStream != null)            {                fileStream.Flush();                fileStream.Close();                fileStream.Dispose();                fileStream = null;            }        }    }    public class OXSheet    {        //定义WorksheetPart子元素节点        private WorksheetPart worksheetPart = null;        private SharedStringTable sharedStringTable = null;        //SheetData:记录非空单元格的位置及内容        private SheetData sheetData = null;        //指向当前行Row        private Row currentRow = null;        //根据ASCII码获取字母A的int编码值        private int begin = 'A' - 1;        public OXSheet(WorksheetPart worksheetPart, SharedStringTable sharedStringTable)        {            this.worksheetPart = worksheetPart;            sheetData = worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault();            currentRow = sheetData.Elements<Row>().LastOrDefault();            if (currentRow == null)            {                AddRow();            }            this.sharedStringTable = sharedStringTable;        }        //添加一行        public void AddRow()        {            currentRow = new Row();            sheetData.AppendChild(currentRow);        }        //在当前行中添加一个的普通表格        public void AddCell(object data)        {            addCell(data, -1);        }        //在当前行中添加一个指定表格样式的普通表格        public void AddCell(object data, int styleIndex)        {            addCell(data, styleIndex);        }        private void addCell(object data, int styleIndex)        {            Cell cell = currentRow.AppendChild(new Cell()            {                //CellValue:单元格内容                CellValue = new CellValue() { Text = data.ToString() },                //DataType:单元格类型                DataType = CellValues.String,            });            if (styleIndex != -1)            {                cell.StyleIndex = (uint)styleIndex;            }        }        //在当前行中添加一个类型为共享字符串的表格        public void AddSharedStringCell(object data)        {            addSharedStringCell(data, -1);        }        //在当前行中添加一个类型为共享字符串、指定表格样式的表格        public void AddSharedStringCell(object data, int styleIndex)        {            addSharedStringCell(data, styleIndex);        }        private void addSharedStringCell(object data, int styleIndex)        {            Cell cell = currentRow.AppendChild(new Cell()            {                CellValue = new CellValue(                    Convert.ToString(getSharedStringItemIndex(data.ToString()))),                DataType = CellValues.SharedString,            });            if (styleIndex != -1)            {                cell.StyleIndex = (uint)styleIndex;            }        }        //获取指定字符串在SharedStringTable中的索引值,不存在就创建        private int getSharedStringItemIndex(string value)        {            //字符串从0开始标记            int index = 0;            //寻找是否有与value相同的字符串,若有,则将index设置为对应的标记值,并返回            //SharedStringItem:共享字符串的数据类型            //sharedStringTable:共享字符串表            foreach (SharedStringItem item in sharedStringTable.Elements<SharedStringItem>())            {                if (item.InnerText == value)                {                    return index;                }                index++;            }            //若没有与value相同的字符串,则添加一个字符串到共享字符串表中,并将其内容设置为value            sharedStringTable.AppendChild(new SharedStringItem(new Text(value)));            sharedStringTable.Save();            return index;        }        //在当前行中添加一个超链接表格        public void AddHyperLink(object data)        {            addHyperlink(data, -1);        }        //在当前行中添加一个超链接表格        public void AddHyperLink(object data, int styleIndex)        {            addHyperlink(data, styleIndex);        }        private void addHyperlink(object data, int styleIndex)        {            Cell cell = currentRow.AppendChild(new Cell()            {                CellFormula = new CellFormula() { Text = string.Format("HYPERLINK({0}{1}{0},{0}{1}{0})", "\"", data.ToString()) },                CellValue = new CellValue(data.ToString()),                DataType = CellValues.String,            });            if (styleIndex != -1)            {                cell.StyleIndex = (uint)styleIndex;            }        }        //指定行和列定位表格,写入数据        public void Write(int rowIndex, int colIndex, object data)        {            Cell cell = getCell(getRow(rowIndex), colIndex);            cell.CellValue = new CellValue(data.ToString());        }        //读取指定行和列的内容        public string Read(int rowIndex, int colIndex)        {            Row row = getRow(rowIndex);            Cell cell = getCell(row, colIndex);            string value = string.Empty;            if (cell.CellValue != null && cell.CellValue.InnerText != null)            {                value = cell.CellValue.InnerText;                if (cell.DataType != null && cell.DataType == CellValues.SharedString)                {                    return sharedStringTable.ElementAt(Int32.Parse(value)).InnerText;                }                else                {                    return value;                }            }            return value;        }        //根据行索引值获取列Row        private Row getRow(int rowIndex)        {            Row row = sheetData.Elements<Row>().FirstOrDefault(r => r != null && r.RowIndex != null && r.RowIndex == rowIndex);            if (row == null)            {                row = new Row() { RowIndex = (uint)rowIndex };                Row lastRow = sheetData.Elements<Row>().LastOrDefault();                if ((lastRow != null && lastRow.RowIndex != null && lastRow.RowIndex < rowIndex) || lastRow == null)                {                    sheetData.AppendChild(row);                }                else                {                    Row refRow = sheetData.Elements<Row>().FirstOrDefault(r => r != null && r.RowIndex != null && r.RowIndex > rowIndex);                    sheetData.InsertBefore(row, refRow);                }            }            return row;        }        //根据指定行和列索引获取单元格Cell        private Cell getCell(Row row, int colIndex)        {            Cell cell = row.Elements<Cell>().FirstOrDefault(c => c != null && c.CellReference != null && c.CellReference.Value == getColNameByColIndex(colIndex) + row.RowIndex);            if (cell == null)            {                cell = new Cell() { CellReference = getColNameByColIndex(colIndex) + row.RowIndex, DataType = CellValues.String };                Cell lastCell = row.Elements<Cell>().LastOrDefault();                if ((lastCell != null && getColIndexByCellReference(lastCell.CellReference.Value) < colIndex) || lastCell == null)                {                    row.AppendChild(cell);                }                else                {                    Cell nextCell = row.Elements<Cell>().FirstOrDefault(c => c != null && c.CellReference != null && getColIndexByCellReference(c.CellReference.Value) > colIndex);                    row.InsertBefore(cell, nextCell);                }            }            return cell;        }        //根据第一行中的表格内容,通过与给定的字符串进行匹配获取列的索引值        public int GetColIndexByHeaderName(string headerName)        {            int index = 1;            Row row = getRow(1);            foreach (Cell cell in row.Elements<Cell>())            {                if (cell != null && cell.CellValue != null && cell.CellValue.InnerText != null &&                    cell.CellValue.InnerText == headerName)                {                    return index;                }                index++;            }            row.AppendChild(new Cell() { CellValue = new CellValue() { Text = headerName.ToString() } });            return index;        }        //根据表格的索引值(如A1)获取列的索引值        private int getColIndexByCellReference(string cellReference)        {            System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"[A-Z]{1,}");            System.Text.RegularExpressions.Match match = regex.Match(cellReference);            string value = match.Value;            return getColIndexByColName(value);        }        //根据列的名称(如A)获取列的索引值        private int getColIndexByColName(string colName)        {            int index = 0;            char[] names = colName.ToCharArray();            int length = names.Length;            for (int i = 0; i < length; i++)            {                index += (names[i] - begin) * (int)Math.Pow(26, length - i - 1);            }            return index;        }        //根据列的索引值获取列名(如A)        private string getColNameByColIndex(int index)        {            string colName = "";            if (index < 0)            {                return colName;            }            while (index > 26)            {                colName += ((char)(index % 26 + begin)).ToString();                index = index / 26;            }            colName += ((char)(index % 26 + begin)).ToString();            return colName;        }        //保存工作表        public void Save()        {            worksheetPart.Worksheet.Save();        }    }}

1 0
原创粉丝点击