【问题标题】:Export DataTable to Excel with Open Xml SDK in c#在 c# 中使用 Open Xml SDK 将 DataTable 导出到 Excel
【发布时间】: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并且非常慢。我的问题只是出口。但是,我现在不想重写很多代码:)

标签: c# excel openxml openxml-sdk


【解决方案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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-15
          • 2012-11-20
          相关资源
          最近更新 更多