在 c# 中使用 Open Xml SDK 将 DataTable 导出到 Excel

     2023-03-30     242

关键词:

【中文标题】在 c# 中使用 Open Xml SDK 将 DataTable 导出到 Excel【英文标题】:Export DataTable to Excel with Open Xml SDK in c# 【发布时间】:2012-08-04 18:42:59 【问题描述】:

我的程序能够将一些数据和 DataTable 导出到 Excel 文件(模板) 在模板中,我将数据插入到一些占位符中。它工作得很好,但我也需要插入一个 DataTable ...... 我的示例代码:

using (Stream OutStream = new MemoryStream())

    // read teamplate
    using (var fileStream = File.OpenRead(templatePath))
        fileStream.CopyTo(OutStream);

    // exporting
    Exporting(OutStream);
         
    // to start
    OutStream.Seek(0L, SeekOrigin.Begin);
            
    // out
    using (var resultFile = File.Create(resultPath))
        OutStream.CopyTo(resultFile);

下一个导出方法

private void Exporting(Stream template)

    using (var workbook = SpreadsheetDocument.Open(template, true, new OpenSettings                           AutoSave = true ))
    
        // Replace shared strings
        SharedStringTablePart sharedStringsPart = workbook.WorkbookPart.SharedStringTablePart;
        IEnumerable<Text> sharedStringTextElements = sharedStringsPart.SharedStringTable.Descendants<Text>();
           
        DoReplace(sharedStringTextElements);
        // Replace inline strings
        IEnumerable<WorksheetPart> worksheetParts = workbook.GetPartsOfType<WorksheetPart>();
          
        foreach (var worksheet in worksheetParts)
        
            DoReplace(worksheet.Worksheet.Descendants<Text>());
        

        int z = 40;
        foreach (System.Data.DataRow row in ExcelWorkXLSX.ToOut.Rows)
        
            for (int i = 0; i < row.ItemArray.Count(); i++)
             
                ExcelWorkXLSX.InsertText(workbook, row.ItemArray.ElementAt(i).ToString(), getColumnName(i), Convert.ToUInt32(z)); 
                z++;
            
         
        
    

但是这个片段输出DataTable slooooooooooooooooooooowwwwwww...

如何快速、真实地将 DataTable 导出到 Excel?

【问题讨论】:

需要使用open xml sdk吗? 嗯...不,但打开 xml sdk 快速读/写 excel 文件。在我的程序中,我读取 xlsx 文件,将数据抓取到 datagridview(使用 DataTable),重新检查数据。首先我使用互操作,但它需要excel并且非常慢。我的问题只是出口。但是,我现在不想重写很多代码:) 【参考方案1】:

我写了这个简单的例子。这个对我有用。我只用一个数据集测试了它,里面有一张表,但我想这对你来说可能就足够了。

考虑到我将所有单元格视为字符串(甚至不是 SharedStrings)。如果您想使用 SharedStrings,您可能需要稍微调整一下我的示例。

编辑:要完成这项工作,需要将 WindowsBase 和 DocumentFormat.OpenXml 引用添加到项目中。

享受,

private void ExportDataSet(DataSet ds, string destination)
        
            using (var workbook = SpreadsheetDocument.Create(destination, DocumentFormat.OpenXml.SpreadsheetDocumentType.Workbook))
            
                var workbookPart = workbook.AddWorkbookPart();

                workbook.WorkbookPart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook();

                workbook.WorkbookPart.Workbook.Sheets = new DocumentFormat.OpenXml.Spreadsheet.Sheets();

                foreach (System.Data.DataTable table in ds.Tables) 

                    var sheetPart = workbook.WorkbookPart.AddNewPart<WorksheetPart>();
                    var sheetData = new DocumentFormat.OpenXml.Spreadsheet.SheetData();
                    sheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet(sheetData);

                    DocumentFormat.OpenXml.Spreadsheet.Sheets sheets = workbook.WorkbookPart.Workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>();
                    string relationshipId = workbook.WorkbookPart.GetIdOfPart(sheetPart);

                    uint sheetId = 1;
                    if (sheets.Elements<DocumentFormat.OpenXml.Spreadsheet.Sheet>().Count() > 0)
                    
                        sheetId =
                            sheets.Elements<DocumentFormat.OpenXml.Spreadsheet.Sheet>().Select(s => s.SheetId.Value).Max() + 1;
                    

                    DocumentFormat.OpenXml.Spreadsheet.Sheet sheet = new DocumentFormat.OpenXml.Spreadsheet.Sheet()  Id = relationshipId, SheetId = sheetId, Name = table.TableName ;
                    sheets.Append(sheet);

                    DocumentFormat.OpenXml.Spreadsheet.Row headerRow = new DocumentFormat.OpenXml.Spreadsheet.Row();

                    List<String> columns = new List<string>();
                    foreach (System.Data.DataColumn column in table.Columns) 
                        columns.Add(column.ColumnName);

                        DocumentFormat.OpenXml.Spreadsheet.Cell cell = new DocumentFormat.OpenXml.Spreadsheet.Cell();
                        cell.DataType = DocumentFormat.OpenXml.Spreadsheet.CellValues.String;
                        cell.CellValue = new DocumentFormat.OpenXml.Spreadsheet.CellValue(column.ColumnName);
                        headerRow.AppendChild(cell);
                    


                    sheetData.AppendChild(headerRow);

                    foreach (System.Data.DataRow dsrow in table.Rows)
                    
                        DocumentFormat.OpenXml.Spreadsheet.Row newRow = new DocumentFormat.OpenXml.Spreadsheet.Row();
                        foreach (String col in columns)
                        
                            DocumentFormat.OpenXml.Spreadsheet.Cell cell = new DocumentFormat.OpenXml.Spreadsheet.Cell();
                            cell.DataType = DocumentFormat.OpenXml.Spreadsheet.CellValues.String;
                            cell.CellValue = new DocumentFormat.OpenXml.Spreadsheet.CellValue(dsrow[col].ToString()); //
                            newRow.AppendChild(cell);
                        

                        sheetData.AppendChild(newRow);
                    

                
            
        

【讨论】:

我认为 workbook.WorkbookPart.Workbook = new...workbook.WorkbookPart.Workbook.Sheets = new 应该移到 foreach 循环之外。否则,循环的每次迭代都会替换工作表,导致 excel 文件仅包含最终的 DataTable @Brian ,感谢您指出这一点。它最初是有效的,因为我只用一张桌子进行了测试。我刚刚修好了,现在还好吗? 是的,看起来不错。顺便说一句,调用 .Max(s=&gt;s.SheetId.Value) 比调用 .Select(s=&gt;s.SheetId.Value).Max() 更干净。同样,您不需要List&lt;String&gt; columns,因为DataRow 有一个DataColumn 索引器;第二个foreach 也可以迭代table.Columns 哦,好吧,我猜这只是为了教育目的:) 谢谢 我自己想通了。要完成这项工作,有必要向项目添加WindowsBaseDocumentFormat.OpenXml 引用。 SpreadsheetDocumentWorksheetPart 也在 DocumentFormat.OpenXml.Packaging 命名空间中【参考方案2】:

eburgos,我稍微修改了您的代码,因为当您的数据集中有多个数据表时,它只是在电子表格中覆盖它们,因此您在工作簿中只剩下一张工作表。我基本上只是将创建工作簿的部分移出循环。这是更新后的代码。

private void ExportDSToExcel(DataSet ds, string destination)

    using (var workbook = SpreadsheetDocument.Create(destination, DocumentFormat.OpenXml.SpreadsheetDocumentType.Workbook))
    
        var workbookPart = workbook.AddWorkbookPart();
        workbook.WorkbookPart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook();
        workbook.WorkbookPart.Workbook.Sheets = new DocumentFormat.OpenXml.Spreadsheet.Sheets();

        uint sheetId = 1;

        foreach (DataTable table in ds.Tables)
        
            var sheetPart = workbook.WorkbookPart.AddNewPart<WorksheetPart>();
            var sheetData = new DocumentFormat.OpenXml.Spreadsheet.SheetData();
            sheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet(sheetData);                

            DocumentFormat.OpenXml.Spreadsheet.Sheets sheets = workbook.WorkbookPart.Workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>();
            string relationshipId = workbook.WorkbookPart.GetIdOfPart(sheetPart);

            if (sheets.Elements<DocumentFormat.OpenXml.Spreadsheet.Sheet>().Count() > 0)
            
                sheetId =
                    sheets.Elements<DocumentFormat.OpenXml.Spreadsheet.Sheet>().Select(s => s.SheetId.Value).Max() + 1;
            

            DocumentFormat.OpenXml.Spreadsheet.Sheet sheet = new DocumentFormat.OpenXml.Spreadsheet.Sheet()  Id = relationshipId, SheetId = sheetId, Name = table.TableName ;
            sheets.Append(sheet);

            DocumentFormat.OpenXml.Spreadsheet.Row headerRow = new DocumentFormat.OpenXml.Spreadsheet.Row();

            List<String> columns = new List<string>();
            foreach (DataColumn column in table.Columns)
            
                columns.Add(column.ColumnName);

                DocumentFormat.OpenXml.Spreadsheet.Cell cell = new DocumentFormat.OpenXml.Spreadsheet.Cell();
                cell.DataType = DocumentFormat.OpenXml.Spreadsheet.CellValues.String;
                cell.CellValue = new DocumentFormat.OpenXml.Spreadsheet.CellValue(column.ColumnName);
                headerRow.AppendChild(cell);
            

            sheetData.AppendChild(headerRow);

            foreach (DataRow dsrow in table.Rows)
            
                DocumentFormat.OpenXml.Spreadsheet.Row newRow = new DocumentFormat.OpenXml.Spreadsheet.Row();
                foreach (String col in columns)
                
                    DocumentFormat.OpenXml.Spreadsheet.Cell cell = new DocumentFormat.OpenXml.Spreadsheet.Cell();
                    cell.DataType = DocumentFormat.OpenXml.Spreadsheet.CellValues.String;
                    cell.CellValue = new DocumentFormat.OpenXml.Spreadsheet.CellValue(dsrow[col].ToString()); //
                    newRow.AppendChild(cell);
                

                sheetData.AppendChild(newRow);
            
        
    

【讨论】:

谢谢,刚刚看到布赖恩的评论,我也做了同样的事情。【参考方案3】:

我还写了一个 C#/VB.Net “导出到 Excel” 库,它使用 OpenXML 并且(更重要的是)也使用 OpenXmlWriter,因此在编写大文件时不会耗尽内存。

完整的源代码和演示可以在这里下载:

Export to Excel

它非常容易使用。 只需将您要写入的文件名和DataTableDataSetList&lt;&gt; 传递给它。

CreateExcelFile.CreateExcelDocument(myDataSet, "MyFilename.xlsx");

如果您从 ASP.Net 应用程序调用它,请将 HttpResponse 传递给它以将文件写入。

CreateExcelFile.CreateExcelDocument(myDataSet, "MyFilename.xlsx", Response);

【讨论】:

对不起...!它现在又活过来了。 @MikeGledhill 是否有任何异步解决方法?尝试写入大文件时出现内存不足异常,我已经阅读了所有相关帖子,似乎它仅限于可用内存? @Afr0:不应该这样。我的库使用 OpenXmlWriter 来写出数据,而不是先尝试在内存中构建整个 Excel 文件。如果可能,请通过我的网站给我发电子邮件,我会看看是否可以提供帮助。 可能我得到的代码库的编写方式不太清楚。【参考方案4】:

我编写了自己的导出到 Excel 编写器,因为没有其他东西完全满足我的需求。它速度很快,并允许对单元格进行大量格式化。您可以在

查看它

https://openxmlexporttoexcel.codeplex.com/

希望对你有帮助。

【讨论】:

【参考方案5】:

您可以尝试看看这个库。我已将它用于我的一个项目,发现它非常易于使用、可靠且快速(我仅将其用于导出数据)。

http://epplus.codeplex.com/

【讨论】:

谢谢!这是一个想法!我会尝试仅用于出口。【参考方案6】:

你可以看看我的图书馆here。在文档部分下,您将找到如何导入数据表。

你只需要写

using (var doc = new SpreadsheetDocument(@"C:\OpenXmlPackaging.xlsx")) 
    Worksheet sheet1 = doc.Worksheets.Add("My Sheet");
    sheet1.ImportDataTable(ds.Tables[0], "A1", true);

希望对你有帮助!

【讨论】:

【参考方案7】:

我尝试了接受的答案,但在尝试打开时收到消息说生成的 excel 文件已损坏。我可以通过一些修改来修复它,比如在代码的行尾添加。

workbookPart.Workbook.Save();

我已经发布了完整代码@Export DataTable to Excel with Open XML in c#

【讨论】:

【参考方案8】:

我想添加这个答案,因为我使用了这个问题的主要答案作为我使用 OpenXML 从数据表导出到 Excel 的基础,但是当我发现它比上述方法快得多时转换到 OpenXMLWriter。

您可以在下面链接中的我的回答中找到完整的详细信息。不过我的代码是在 VB.NET 中的,所以你必须转换它。

How to export DataTable to Excel

【讨论】:

如何从 Word 文档中复制富文本内容控件的内容并使用 Open XML SDK 删除控件本身

】如何从Word文档中复制富文本内容控件的内容并使用OpenXMLSDK删除控件本身【英文标题】:HowtocopycontentofRichTextContentControlfromWorddocumentandremovethecontrolitselfusingOpenXMLSDK【发布时间】:2021-04-2716:58:08【问题描述】:我正在尝试将富文... 查看详情

如何使用 c# 在 Open Office Calc 表中插入超过 256 列?

】如何使用c#在OpenOfficeCalc表中插入超过256列?【英文标题】:Howtoinsertmorethan256columnsinaOpenOfficeCalcsheetusingc#?【发布时间】:2010-03-1112:22:25【问题描述】:嗨!朋友我的表格包含457列,我需要将此表格数据导出到OpenOfficeCalc电子表... 查看详情

在 C# 中,如何使用大量精美的标记将 POCO 序列化为 XML?

】在C#中,如何使用大量精美的标记将POCO序列化为XML?【英文标题】:InC#,howcanIserializeaPOCOtoXMLwithalotoffancymarkup?【发布时间】:2021-11-1500:41:55【问题描述】:要使用SOAP服务,我需要以XML格式发送消息,如下所示:<soap:Envelopexmln... 查看详情

如何在 C# 中使用添加的自定义标签将 JSON 转换为 XML

】如何在C#中使用添加的自定义标签将JSON转换为XML【英文标题】:HowtoconvertJSONtoXMLwithaddedcustomtaginC#【发布时间】:2021-11-1010:40:13【问题描述】:我有一些这种格式的JSON示例:"id":"532-513jg-5ujkl-5jiklf","externalGuid":"93804jlkfes","tagNumber"... 查看详情

如何在 C# 控制台应用程序中使用 XmlTextReader 将 XML 数据插入 SQL Server 表?

】如何在C#控制台应用程序中使用XmlTextReader将XML数据插入SQLServer表?【英文标题】:HowtoinsertXMLdataintoSQLServertableusingXmlTextReaderinC#consoleapp?【发布时间】:2018-12-2023:50:50【问题描述】:我有一个4GB的XML文件。我必须将它的一些值插... 查看详情

使用 C# 在 XML 文件中选择节点属性

】使用C#在XML文件中选择节点属性【英文标题】:SelectnodesattributeinXMLfileusingC#【发布时间】:2014-02-1210:07:34【问题描述】:在以下XML文件中,我尝试将所有id属性保存在一个列表中:<?xmlversion="1.0"?><PressReleases><PressReleas... 查看详情

在 C# 桌面应用程序中使用 Open*** 实现拆分和隧道

】在C#桌面应用程序中使用Open***实现拆分和隧道【英文标题】:ImplementSplitandTunnelingusingOpen***inC#desktopapplication【发布时间】:2021-10-2603:54:14【问题描述】:我创建了使用Open***Community连接到***服务器的应用程序,它工作正常并且... 查看详情

我应该在哪里使用 C# 调用方法 connection.Open()?

】我应该在哪里使用C#调用方法connection.Open()?【英文标题】:WhereamIsupposedtocallthemethodconnection.Open()usingC#?【发布时间】:2014-02-0919:02:46【问题描述】:您好,我正在尝试从文本框中显示的数据库中获取数据。为此,我创建了三个... 查看详情

有没有办法在 python 中运行 C# 的不和谐 SDK 代码?

...0-09-1815:40:56【问题描述】:我试图在我的python应用程序上使用discordSDK,唯一的非统一和非虚幻方法是使用C#我完全不知道如何用C#编写代码,但Discord说我只需要一行代码我尝试将我的应用程序转换为C#,但C#不支持pyth 查看详情

使用 C# 将 xml 反序列化为超类对象

】使用C#将xml反序列化为超类对象【英文标题】:DeserializexmlintosuperclassobjectwithC#【发布时间】:2013-06-2123:20:41【问题描述】:我正在创建一个程序,允许用户使用4种基本操作定义公式:使用XML的加法、减法、除法、乘法。举个... 查看详情

在c#中保存xml文件

】在c#中保存xml文件【英文标题】:Savexmlfileinc#【发布时间】:2014-06-0121:43:02【问题描述】:我有一个程序,它将接受名称和分数,它将分数与位于xml文件中的记分板进行比较,然后将其从最高到最低排序。它一直有效,直到我... 查看详情

在 C# 中使用设置类

】在C#中使用设置类【英文标题】:UsingSettingsClassinC#【发布时间】:2012-11-2408:36:00【问题描述】:我正在使用Properties.Settings类来保存应用程序设置。我想知道,一旦我在客户端系统中部署,设置是否会在应用程序重启和系统重... 查看详情

在 C# 中使用 XML 文字?

】在C#中使用XML文字?【英文标题】:UseXMLLiteralsinC#?【发布时间】:2021-05-2210:37:27【问题描述】:是否可以在C#代码文件中添加文字XML数据?我目前正在使用多行字符串文字,但如您所见,它变得混乱。有更好的方法吗?stringXML=... 查看详情

为 AWS C# S3 SDK 使用内存流而不是文件流而不将完整文件写入 S3

】为AWSC#S3SDK使用内存流而不是文件流而不将完整文件写入S3【英文标题】:UsingmemorystreaminsteadoffilestreamforAWSC#S3SDKnotwritingfullfiletoS3【发布时间】:2021-12-2814:58:19【问题描述】:我有一些用于在AWSS3存储桶上创建文件的代码。当我... 查看详情

在 C# 中安全地解析 XML

...变的,并且在完成处理后我无法擦除这些值。我目前正在使用System.XML.XmlReader将值解析为字符串(参见下面的代码)。在不让我的代 查看详情

如何将datagridview导出到Open Office Excel c#

...dview导出到OpenOfficeExcel。我不知道在我的OpenOffice项目中要使用哪些 查看详情

将 XML 转换为动态 C# 对象

...amicC#object【发布时间】:2012-10-2117:06:25【问题描述】:我使用以下C#代码通过JSON.Net框架将JSON数据字符串转换为动态对象://Createsadynamic.NetobjectrepresentingtheJSONdatavarProductDB=JsonConvert.DeserializeObject<d 查看详情

在 C# 中使用 Xmldocument 修改 xml

】在C#中使用Xmldocument修改xml【英文标题】:ModifyxmlwithXmldocumentinC#【发布时间】:2021-11-2822:27:24【问题描述】:我正在尝试按照此处HowtomodifyexistingXMLfilewithXmlDocumentandXmlNodeinC#的另一篇文章中的说明编辑xml文档的值。这是我的代码... 查看详情