Brian Vallelunga
Brian Vallelunga

Reputation: 10191

Efficiently generate a very large Excel file in .NET?

I need to generate a very large Excel file from an ASP.NET MVC site, but am running into memory limitations using the Open XML SDK. Is there a memory efficient way to generate such a file?

For reference, I'm trying to generate a spreadsheet with about 500,000 rows with 20 columns each. The data set itself fits into memory just fine, but the Open XML SDK quickly eats up all of my available memory.

Upvotes: 5

Views: 5741

Answers (1)

rsciriano
rsciriano

Reputation: 268

You can use Open XML SDK in reasonably efficiently way, the trick is to use the OpenXmlWriter class (in this CodeProject article you have more details)

I had a memory issue generating a file of 91 columns x 164,000 rows. Using OpenXmlWriter I went from 2GB of RAM consumption to 120MB, enough for me :-)

Seeing it with a code example:

Standard (and unoptimized) way:

// Table header
Row headerRow = new Row();
foreach (string fieldName in fields)
{
    Cell cell = new Cell();
    cell.DataType = CellValues.String;
    cell.CellValue = new CellValue(fieldName);
    headerRow.AppendChild(cell);
}
sheetData.AppendChild(headerRow);

// Table rows
while (dataReader.Read())
{
    Row dataRow = new Row();

    foreach (string fieldName in fields)
    {
        Cell cell = new Cell();
        cell.DataType = CellValues.String;
        cell.CellValue = new CellValue(reader[fieldName].ToString());
        dataRow.AppendChild(cell);
    }

    sheetData.AppendChild(dataRow);
}

OpenXmlWriter way:

using (var writer = OpenXmlWriter.Create(worksheetPart))
{
    writer.WriteStartElement(new Worksheet());
    writer.WriteStartElement(new SheetData());

    // Table header
    writer.WriteStartElement(new Row());
    foreach (string fieldName in fields)
    {
        writer.WriteStartElement(new Cell() { DataType = CellValues.String });
        writer.WriteElement(new CellValue(fieldName));
        writer.WriteEndElement();        
    }
    writer.WriteEndElement(); //end of Row tag

    // Table rows
    while (dataReader.Read())
    {
        writer.WriteStartElement(new Row());

        foreach (string fieldName in fields)
        {
            writer.WriteStartElement(new Cell() { DataType = CellValues.String });
            writer.WriteElement(new CellValue(dataReader[fieldName].ToString()));
            writer.WriteEndElement();        
        }

        writer.WriteEndElement(); //end of Row tag
    }

    writer.WriteEndElement(); //end of SheetData
    writer.WriteEndElement(); //end of worksheet
    writer.Close();
}

Upvotes: 3

Related Questions