【问题标题】:More efficient way to write data table to excel?将数据表写入excel的更有效方法?
【发布时间】:2015-02-14 17:38:52
【问题描述】:

在我的WPF 应用程序中,我有一个巨大的数据表 (System.Data.DataTable),我需要将其写入 Excel 文档中的工作表。函数的重头部分:

        for (; i < dt.Rows.Count; i++)
        {
            for (int colNum = 0; colNum < dt.Columns.Count; colNum++)
                newSheet.Cells[i + rowNumber, colNum + 1] = dt.Rows[i][colNum].ToString();
            applyRowBorderStyle(newSheet, i + rowNumber, dt.Columns.Count);
        }

dt 是 DataTable,neewSheet 是我写入的 excel 表,applyRowBorderStyle(..) 为行中的所有单元格添加边框。当数据表很大时,它运行非常慢,可能需要 10 分钟甚至更长时间。有什么办法让它跑得更快?


编辑:程序分析了很多数据,做了很多工作表,我不能让用户做任何事情。我必须只使用 Microsoft Excel。此工作表始终有 42 列,但行数会根据程序接收到的数据量而变化,约 500 行。 "applyRowBorderStyle" 会让代码跑得快一点,但是不符合要求。。真希望有别的办法让它跑得更快。。

【问题讨论】:

  • 只需在您的应用程序中为用户提供复制和粘贴选项。添加一个包含复制按钮的菜单 - 单击该按钮会将 DataTable 中的选定行作为文本复制到剪贴板中,然后用户可以将其粘贴到 excel 中。
  • 如果你删除applyRowBorderStyle怎么样?当你说“大”时,它有多大?
  • 是否可以将其另存为 CSV。这是一个简单的文件,所以不需要使用 Excel 互操作。
  • 这可能会有所帮助codeproject.com/Articles/21519/…
  • 查看EPPlus library,它的性能非常好,插入 30k 行时性能非常好,在最近的版本中,50k 行具有相同的性能。

标签: c# wpf excel performance datatable


【解决方案1】:

找到了答案!这是我写的函数,以及我使用的参考:http://www.codeproject.com/Articles/21519/Fast-Exporting-from-DataSet-to-Excel

private void FastDtToExcel(System.Data.DataTable dt, Worksheet sheet, int firstRow, int firstCol, int lastRow, int lastCol)
    {
        Range top = sheet.Cells[firstRow, firstCol];
        Range bottom = sheet.Cells[lastRow, lastCol];
        Range all = (Range)sheet.get_Range(top, bottom);
        string[,] arrayDT = new string[dt.Rows.Count, dt.Columns.Count];
        for (int i = 0; i < dt.Rows.Count; i++)
            for (int j = 0; j < dt.Columns.Count; j++)
                arrayDT[i, j] = dt.Rows[i][j].ToString();
        all.Value2 = arrayDT;
    }

不到一秒钟,这太棒了:)

【讨论】:

    【解决方案2】:

    我一直发现将数据表转换为 Excel 的最有效方法是将数据表转换为 adodb.recordset。
    重要的是使用 excels CopyFromRecordSet 方法
    objWorksheet.Range("A1").CopyFromRecordset(ConvertToRecordset(dt))

    刚刚进行了几次比较,下面是结果。

    5 万条记录

    数据表到 excel = 1 分 6 秒
    数据表到 RS 到 Excel = 2 秒

    25 万条记录

    数据表到 excel = 5 分 29 秒
    数据表到 RS 到 Excel = 10 秒

    以下内容显然是用 vb.net 编写的,因此您需要将代码转换为 C# 以供您的应用程序使用,但希望对您有所帮助。

    Public Class Form1
    
        Private dt As New DataTable
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    
            dt.Columns.Add("header1")
            dt.Columns.Add("header2")
            dt.Columns.Add("header3")
            dt.Columns.Add("header4")
    
            For i = 0 To 250000
                dt.Rows.Add({i, i, i, i})
            Next
    
        End Sub
    
        Private Sub DataTableConvBtn_Click(sender As System.Object, e As System.EventArgs) Handles DataTableConvBtn.Click
    
            Dim starttime = Now.ToString
            Dim objExcel = CreateObject("Excel.Application")
            objExcel.Visible = True
            Dim objWorkbook = objExcel.Workbooks.Add()
            Dim objWorksheet = objWorkbook.Worksheets(1)
    
            objWorksheet.Range("A1").CopyFromRecordset(ConvertToRecordset(dt))
    
            Dim endtime = Now.ToString
    
            MsgBox(starttime & vbCrLf & endtime)
    
    
    
        End Sub
    
        Public Shared Function ConvertToRecordset(ByVal inTable As DataTable) As ADODB.Recordset
    
            Dim result As ADODB.Recordset = New ADODB.Recordset()
            result.CursorLocation = ADODB.CursorLocationEnum.adUseClient
            Dim resultFields As ADODB.Fields = result.Fields
            Dim inColumns As System.Data.DataColumnCollection = inTable.Columns
    
            For Each inColumn As DataColumn In inColumns
                resultFields.Append(inColumn.ColumnName, TranslateType(inColumn.DataType), inColumn.MaxLength, ADODB.FieldAttributeEnum.adFldIsNullable, Nothing)
            Next
    
            result.Open(System.Reflection.Missing.Value, System.Reflection.Missing.Value, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockOptimistic)
    
            For Each dr As DataRow In inTable.Rows
                result.AddNew(System.Reflection.Missing.Value, System.Reflection.Missing.Value)
    
                For columnIndex As Integer = 0 To inColumns.Count - 1
                    resultFields(columnIndex).Value = dr(columnIndex)
                Next
            Next
    
            Return result
    
        End Function
    
        Shared Function TranslateType(ByVal columnType As Type) As ADODB.DataTypeEnum
    
            Select Case columnType.UnderlyingSystemType.ToString()
                Case "System.Boolean"
                    Return ADODB.DataTypeEnum.adBoolean
                Case "System.Byte"
                    Return ADODB.DataTypeEnum.adUnsignedTinyInt
                Case "System.Char"
                    Return ADODB.DataTypeEnum.adChar
                Case "System.DateTime"
                    Return ADODB.DataTypeEnum.adDate
                Case "System.Decimal"
                    Return ADODB.DataTypeEnum.adCurrency
                Case "System.Double"
                    Return ADODB.DataTypeEnum.adDouble
                Case "System.Int16"
                    Return ADODB.DataTypeEnum.adSmallInt
                Case "System.Int32"
                    Return ADODB.DataTypeEnum.adInteger
                Case "System.Int64"
                    Return ADODB.DataTypeEnum.adBigInt
                Case "System.SByte"
                    Return ADODB.DataTypeEnum.adTinyInt
                Case "System.Single"
                    Return ADODB.DataTypeEnum.adSingle
                Case "System.UInt16"
                    Return ADODB.DataTypeEnum.adUnsignedSmallInt
                Case "System.UInt32"
                    Return ADODB.DataTypeEnum.adUnsignedInt
                Case "System.UInt64"
                    Return ADODB.DataTypeEnum.adUnsignedBigInt
            End Select
    
            Return ADODB.DataTypeEnum.adVarChar
    
    
        End Function
    
    
    
        Private Sub DtToExcelBtn_Click(sender As System.Object, e As System.EventArgs) Handles DtToExcelBtn.Click
    
            Dim starttime = Now.ToString
            Dim objExcel = CreateObject("Excel.Application")
            Dim objWorkbook = objExcel.Workbooks.Add()
            Dim objWorksheet = objWorkbook.Worksheets(1)
    
            Dim i = 1
            Dim rownumber = 1
    
            objExcel.Visible = True
    
            Do While (i < dt.Rows.Count)
                Dim colNum As Integer = 0
                Do While (colNum < dt.Columns.Count)
                    objWorksheet.Cells((i + rownumber), (colNum + 1)) = dt.Rows(i)(colNum).ToString
                    colNum = (colNum + 1)
                Loop
                i = (i + 1)
            Loop
    
            Dim endtime = Now.ToString
            MsgBox(starttime & vbCrLf & endtime)
    
    
    
        End Sub
    End Class
    

    【讨论】:

      猜你喜欢
      • 2012-08-06
      • 2021-11-29
      • 2019-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-01
      相关资源
      最近更新 更多