Skip to main content
 首页 » 编程设计

c#之OpenXML 大数据集 excel 很慢

2024年04月12日28zhenyulu

我正在使用 OpenXml 将大数据转换为 excel,我正在使用以下导出到 Excel 类

http://www.codeproject.com/Articles/692092/A-free-Export-to-Excel-Csharp-class-using-OpenXML

下面是我类(class)的代码。

  public static bool CreateExcelDocumentAsStream(DataSet ds, string filename, System.Web.HttpResponse Response) 
    { 
        try 
        { 
            System.IO.MemoryStream stream = new System.IO.MemoryStream(); 
            using (SpreadsheetDocument document = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook, true)) 
            { 
                WriteExcelFile(ds, document); 
            } 
            stream.Flush(); 
            stream.Position = 0; 
 
            Response.ClearContent(); 
            Response.Clear(); 
            Response.Buffer = true; 
            Response.Charset = ""; 
 
            //  NOTE: If you get an "HttpCacheability does not exist" error on the following line, make sure you have 
            //  manually added System.Web to this project's References. 
 
            Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache); 
            Response.AddHeader("content-disposition", "attachment; filename=" + filename); 
            Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; 
            byte[] data1 = new byte[stream.Length]; 
            stream.Read(data1, 0, data1.Length); 
            stream.Close(); 
            Response.BinaryWrite(data1); 
            Response.Flush(); 
 
            //  Feb2015: Needed to replace "Response.End();" with the following 3 lines, to make sure the Excel was fully written to the Response 
            System.Web.HttpContext.Current.Response.Flush(); 
            System.Web.HttpContext.Current.Response.SuppressContent = true; 
            System.Web.HttpContext.Current.ApplicationInstance.CompleteRequest(); 
 
            return true; 
        } 
        catch (Exception ex) 
        { 
            Trace.WriteLine("Failed, exception thrown: " + ex.Message); 
            return false; 
        } 
    } 
 
    /// <summary> 
    /// Create an Excel file, and write it to a file. 
    /// </summary> 
    /// <param name="ds">DataSet containing the data to be written to the Excel.</param> 
    /// <param name="excelFilename">Name of file to be written.</param> 
    /// <returns>True if successful, false if something went wrong.</returns> 
    public static bool CreateExcelDocument(DataSet ds, string excelFilename) 
    { 
        try 
        { 
            using (SpreadsheetDocument document = SpreadsheetDocument.Create(excelFilename, SpreadsheetDocumentType.Workbook)) 
            { 
                WriteExcelFile(ds, document); 
 
            } 
            Trace.WriteLine("Successfully created: " + excelFilename); 
            return true; 
        } 
        catch (Exception ex) 
        { 
            Trace.WriteLine("Failed, exception thrown: " + ex.Message); 
            return false; 
        } 
    } 
 
 
    private static void WriteExcelFile(DataSet ds, SpreadsheetDocument spreadsheet) 
    { 
        //  Create the Excel file contents.  This function is used when creating an Excel file either writing  
        //  to a file, or writing to a MemoryStream. 
        spreadsheet.AddWorkbookPart(); 
        spreadsheet.WorkbookPart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook(); 
 
        //  My thanks to James Miera for the following line of code (which prevents crashes in Excel 2010) 
        spreadsheet.WorkbookPart.Workbook.Append(new BookViews(new WorkbookView())); 
 
        //  If we don't add a "WorkbookStylesPart", OLEDB will refuse to connect to this .xlsx file ! 
        WorkbookStylesPart workbookStylesPart = spreadsheet.WorkbookPart.AddNewPart<WorkbookStylesPart>("rIdStyles"); 
        Stylesheet stylesheet = new Stylesheet(); 
        workbookStylesPart.Stylesheet = stylesheet; 
 
 
        //  Loop through each of the DataTables in our DataSet, and create a new Excel Worksheet for each. 
        uint worksheetNumber = 1; 
        Sheets sheets = spreadsheet.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets()); 
        foreach (DataTable dt in ds.Tables) 
        { 
            //  For each worksheet you want to create 
            string worksheetName = dt.TableName; 
 
            //  Create worksheet part, and add it to the sheets collection in workbook 
            WorksheetPart newWorksheetPart = spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>(); 
            Sheet sheet = new Sheet() { Id = spreadsheet.WorkbookPart.GetIdOfPart(newWorksheetPart), SheetId = worksheetNumber, Name = worksheetName }; 
 
            // If you want to define the Column Widths for a Worksheet, you need to do this *before* appending the SheetData 
            // http://social.msdn.microsoft.com/Forums/en-US/oxmlsdk/thread/1d93eca8-2949-4d12-8dd9-15cc24128b10/ 
 
            sheets.Append(sheet); 
 
            //  Append this worksheet's data to our Workbook, using OpenXmlWriter, to prevent memory problems 
            WriteDataTableToExcelWorksheet(dt, newWorksheetPart); 
 
            worksheetNumber++; 
        } 
 
 
        spreadsheet.WorkbookPart.Workbook.Save(); 
 
 
 
    } 
 
    private static void WriteDataTableToExcelWorksheet(DataTable dt, WorksheetPart worksheetPart) 
    { 
        OpenXmlWriter writer = OpenXmlWriter.Create(worksheetPart, Encoding.ASCII); 
        writer.WriteStartElement(new Worksheet()); 
        writer.WriteStartElement(new SheetData()); 
 
        string cellValue = ""; 
 
        //  Create a Header Row in our Excel file, containing one header for each Column of data in our DataTable. 
        // 
        //  We'll also create an array, showing which type each column of data is (Text or Numeric), so when we come to write the actual 
        //  cells of data, we'll know if to write Text values or Numeric cell values. 
        int numberOfColumns = dt.Columns.Count; 
        bool[] IsNumericColumn = new bool[numberOfColumns]; 
        bool[] IsDateColumn = new bool[numberOfColumns]; 
 
        string[] excelColumnNames = new string[numberOfColumns]; 
        for (int n = 0; n < numberOfColumns; n++) 
            excelColumnNames[n] = GetExcelColumnName(n); 
 
        // 
        //  Create the Header row in our Excel Worksheet 
        // 
        uint rowIndex = 1; 
 
        writer.WriteStartElement(new Row { RowIndex = rowIndex }); 
        for (int colInx = 0; colInx < numberOfColumns; colInx++) 
        { 
            DataColumn col = dt.Columns[colInx]; 
            AppendTextCell(excelColumnNames[colInx] + "1", col.ColumnName, ref writer); 
            IsNumericColumn[colInx] = (col.DataType.FullName == "System.Decimal") || (col.DataType.FullName == "System.Int32") || (col.DataType.FullName == "System.Double") || (col.DataType.FullName == "System.Single"); 
            IsDateColumn[colInx] = (col.DataType.FullName == "System.DateTime"); 
        } 
        writer.WriteEndElement();   //  End of header "Row" 
 
        // 
        //  Now, step through each row of data in our DataTable... 
        // 
        double cellNumericValue = 0; 
        foreach (DataRow dr in dt.Rows) 
        { 
            // ...create a new row, and append a set of this row's data to it. 
            ++rowIndex; 
 
            writer.WriteStartElement(new Row { RowIndex = rowIndex }); 
 
            for (int colInx = 0; colInx < numberOfColumns; colInx++) 
            { 
                cellValue = dr.ItemArray[colInx].ToString(); 
                cellValue = ReplaceHexadecimalSymbols(cellValue); 
 
                // Create cell with data 
                if (IsNumericColumn[colInx]) 
                { 
                    //  For numeric cells, make sure our input data IS a number, then write it out to the Excel file. 
                    //  If this numeric value is NULL, then don't write anything to the Excel file. 
                    cellNumericValue = 0; 
                    if (double.TryParse(cellValue, out cellNumericValue)) 
                    { 
                        cellValue = cellNumericValue.ToString(); 
                        AppendNumericCell(excelColumnNames[colInx] + rowIndex.ToString(), cellValue, ref writer); 
                    } 
                } 
                else if (IsDateColumn[colInx]) 
                { 
                    //  This is a date value. 
                    DateTime dtValue; 
                    string strValue = ""; 
                    if (DateTime.TryParse(cellValue, out dtValue)) 
                        strValue = dtValue.ToShortDateString(); 
                    AppendTextCell(excelColumnNames[colInx] + rowIndex.ToString(), strValue, ref writer); 
                } 
                else 
                { 
                    //  For text cells, just write the input data straight out to the Excel file. 
                    AppendTextCell(excelColumnNames[colInx] + rowIndex.ToString(), cellValue, ref writer); 
                } 
            } 
            writer.WriteEndElement(); //  End of Row 
        } 
        writer.WriteEndElement(); //  End of SheetData 
        writer.WriteEndElement(); //  End of worksheet 
 
        writer.Close(); 
    } 
 
    private static void AppendTextCell(string cellReference, string cellStringValue, ref OpenXmlWriter writer) 
    { 
        //  Add a new Excel Cell to our Row  
        writer.WriteElement(new Cell 
        { 
            CellValue = new CellValue(cellStringValue), 
            CellReference = cellReference, 
            DataType = CellValues.String 
        }); 
    } 
 
    private static void AppendNumericCell(string cellReference, string cellStringValue, ref OpenXmlWriter writer) 
    { 
        //  Add a new Excel Cell to our Row  
        writer.WriteElement(new Cell 
        { 
            CellValue = new CellValue(cellStringValue), 
            CellReference = cellReference, 
            DataType = CellValues.Number 
        }); 
    } 
 
    private static string ReplaceHexadecimalSymbols(string txt) 
    { 
        string r = "[\x00-\x08\x0B\x0C\x0E-\x1F\x26]"; 
        return Regex.Replace(txt, r, "", RegexOptions.Compiled); 
    } 

我是这样调用方法的

            CreateExcelFile.CreateExcelDocumentAsStream(ds, ExportToExcel.FileName, response); 

这工作正常,但它有性能问题并且非常慢。我的 Excel 数据有 49K 行和 100 列。

有没有办法提高性能?

如有任何建议,我们将不胜感激。

提前致谢

请您参考如下方法: