将大量数据写入excel c#

时间:2016-05-30 13:49:19

标签: c# excel openxml-sdk epplus

我需要将大量数据从数据库表导出到excel(xls / xlsx)文件。 它可能很容易1000万行甚至更多。

我需要开源解决方案,不需要安装Office(SpreadsheetGear和互操作解决方案对我不起作用)。

我正在检查两个库:OpenXML SDK和EPPlus。

对于OpenXML SDK,我找到了这个方法:

  private static void Write(string fileName, int numRows, int numCols)
        {
            using (var spreadsheetDocument = SpreadsheetDocument.Open(fileName, true))
            {
                WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
                WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();

                string origninalSheetId = workbookPart.GetIdOfPart(worksheetPart);

                WorksheetPart replacementPart = workbookPart.AddNewPart<WorksheetPart>();
                string replacementPartId = workbookPart.GetIdOfPart(replacementPart);

                using (OpenXmlReader reader = OpenXmlReader.Create(worksheetPart))
                {
                    using (OpenXmlWriter writer = OpenXmlWriter.Create(replacementPart))
                    {
                        Row row = new Row();
                        Cell cell = new Cell();
                        //CellFormula cellFormula = new CellFormula();
                        //cellFormula.CalculateCell = true;
                        //cellFormula.Text = "RAND()";
                        //cell.Append(cellFormula);
                        CellValue cellValue = new CellValue("val val");
                        cell.Append(cellValue);

                        while (reader.Read())
                        {
                            if (reader.ElementType == typeof(SheetData))
                            {
                                if (reader.IsEndElement)
                                    continue;
                                writer.WriteStartElement(new SheetData());

                                for (int rowNumber = 0; rowNumber < numRows; rowNumber++)
                                {
                                    writer.WriteStartElement(row);
                                    for (int col = 0; col < numCols; col++)
                                    {
                                        writer.WriteElement(cell);
                                    }
                                    writer.WriteEndElement();
                                }

                                writer.WriteEndElement();
                            }
                            else
                            {
                                if (reader.IsStartElement)
                                {
                                    writer.WriteStartElement(reader);
                                }
                                else if (reader.IsEndElement)
                                {
                                    writer.WriteEndElement();
                                }
                            }
                        }
                    }
                }

                Sheet sheet = workbookPart.Workbook.Descendants<Sheet>().First(s => s.Id.Value.Equals(origninalSheetId));
                sheet.Id.Value = replacementPartId;
                workbookPart.DeletePart(worksheetPart);
            }
        }

但它会引发Out of memory异常。 我需要batch oriented方法,并能够append数据到excel文档的末尾。 很遗憾,我没有找到如何使用OpenXML SDK附加行。

另外,我使用LoadFromCollection方法检查了EPPlus soluion。 它确实支持IDataReader LoadFromDataReader,但我在代码中没有datareader。

问题:是否有办法将数据附加到现有的工作表xls / xlsx文件中?与OpenXMLWrite中的OpenXML SDK r一样。

UPD。 Excel显然不支持1000万行。让我们坚持使用1m行并丢失列而不会出现内存异常。

UPD。添加了EPPlus样本。 200k行在6分钟内导出,占用1GB内存。

 private const string TempFile = @"C:\Users\vnechyp\Desktop\temp.xlsx";

private static void EPPlusExport()
{
    var random = new Random();

    var dt = new System.Data.DataTable();
    for (int i = 0; i < 15; i++)
    {
        dt.Columns.Add($"column_{i}");
    }

    var values = Enumerable.Range(0, 15).Select(val => random.Next().ToString()).ToArray();

    for (int i = 0; i < 10000; i++)
    {
        dt.Rows.Add(values);
    }

    using (ExcelPackage excelPackage = new ExcelPackage())
    {
        var workSheet = excelPackage.Workbook.Worksheets.Add("sheet");
        workSheet.Cells[1, 1].LoadFromDataTable(dt, true);
        excelPackage.SaveAs(new FileInfo(TempFile));
    }


    for (int i = 1; i < 50; i++)
    {
        Console.WriteLine($"Iteration: {i}");

        var updateRow = i*10000;
        Console.WriteLine($"Rows: {updateRow}");

        FileInfo existingFile = new FileInfo(TempFile);
        using (ExcelPackage excelPackage = new ExcelPackage(existingFile))
        {
            // get the first worksheet in the workbook
            ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[1];
            worksheet.Cells[updateRow, 1].LoadFromDataTable(dt, true);
            excelPackage.SaveAs(new FileInfo(TempFile));
        }
    }
}

2 个答案:

答案 0 :(得分:2)

+-----------------+-----------+--------------+---------------------+
|                 | Max. Rows | Max. Columns | Max. Cols by letter |
+-----------------+-----------+--------------+---------------------+
| Excel 365*      | 1,048,576 | 16,384       | XFD                 |
| Excel 2013      | 1,048,576 | 16,384       | XFD                 |
| Excel 2010      | 1,048,576 | 16,384       | XFD                 |
| Excel 2007      | 1,048,576 | 16,384       | XFD                 |
| Excel 2003      | 65,536    | 256          | IV                  |
| Excel 2002 (XP) | 65,536    | 256          | IV                  |
| Excel 2000      | 65,536    | 256          | IV                  |
| Excel 97        | 65,536    | 256          | IV                  |
| Excel 95        | 16,384    | 256          | IV                  |
| Excel 5         | 16,384    | 256          | IV                  |
+-----------------+-----------+--------------+---------------------+

您可以将csv文件用于1000万行

答案 1 :(得分:0)

我最喜欢导出到Excel的方法,假设CSV不够,就是使用Open XML SDK。下面的解决方案链接到文森特汤姆关于如何实现大数据导出的精彩文章,只是为新用户稍微清理了他的样本。

Export a large data query (60k+ rows) to Excel

当我自己这样做时,我基本上使用Open XML Writer,并且对于IQueryable上的每个循环使用a。永远不要调用ToList(),否则你必须填充一个包含内存中所有数据的列表,这会使整个点失败。

例如,我使用这种技术导出了Excel文件,包含190,000多条记录和87多列,其他我尝试过的Excel库都失败了。