将DataTable转换为CSV的最有效方法

16

我正在处理 DataTable,需要将它们转换为 CSV 文件格式。大部分我处理的表格都有超过 50,000 条记录,因此我正在尝试最小化转换所需的时间。

这是我的目前的方法:

    public static string table_to_csv(DataTable table)
    {
        string file = "";

        foreach (DataColumn col in table.Columns)
            file = string.Concat(file, col.ColumnName, ",");

        file = file.Remove(file.LastIndexOf(','), 1);
        file = string.Concat(file, "\r\n");

        foreach (DataRow row in table.Rows)
        {
            foreach (object item in row.ItemArray)
                file = string.Concat(file, item.ToString(), ",");

            file = file.Remove(file.LastIndexOf(','), 1);
            file = string.Concat(file, "\r\n");
        }

        return file;
    }

有什么办法可以提高这种方法的效率吗?欢迎您提出任何修改和想法!


3
既然你的代码运行正常且没有遇到问题,也许代码审查(Code Review)比StackOverflow更适合你的问题。 - Andrey Korneyev
你为什么要一次性加载这么多行数据呢?使用数据库的工具(如 SQL Server 中的 SSIS)将数据导出到 CSV 文件中会更容易。或者使用 DataReader 以 firehose 模式读取数据并将其写入文件中。在内存中创建整个字符串也不是高效的方法 - 使用 Write 和 WriteLine 将它们写入文件中。此外,您可以使用 String.Join 替换重复的连接,但使用 Write 也使其有点冗余。 - Panagiotis Kanavos
可能是重复的问题 将 DataTable 转换为 CSV 流 - Panagiotis Kanavos
1
我认为这些答案不适合CodeReview,但我也不认为这是离题的。对我来说,“试图最小化将它们转换所需的时间”听起来像一个问题陈述,这可能就是离题的原因。迁移将被拒绝。 - Malachi
3个回答

28

使用System.Text.StringBuilder来处理大字符串,这样可以提高效率。我已经实现了这个方法:

public static string DataTableToCSV(this DataTable datatable, char seperator)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < datatable.Columns.Count; i++)
    {
        sb.Append(datatable.Columns[i]);
        if (i < datatable.Columns.Count - 1)
            sb.Append(seperator);
    }
    sb.AppendLine();
    foreach (DataRow dr in datatable.Rows)
    {
        for (int i = 0; i < datatable.Columns.Count; i++)
        {
            sb.Append(dr[i].ToString());

            if (i < datatable.Columns.Count - 1)
                sb.Append(seperator);
        }
        sb.AppendLine();
    }
    return sb.ToString();
}

2
这个答案符合我的要求,一个包含超过30k条记录的DataTable以前需要几分钟才能完成,现在只需要不到1秒钟。谢谢。 - Mike Eason
1
如何将数据集转换为 CSV? - Deepak Jain
1
@AkhilJain 如果你的 DataSet 中有多个表格 - 你不能这样做。如果你只有一个表格,那么 string result = DataTableToCSV(myDataSet.Tables[0], ','); - fubo
这是一个非常棒的解决方案 - 只想说感谢你帮了我很多忙! - Jared Forth

9

这是我在我的工具类中使用的一种方法。对于我正在做的事情很有效。

 public static void GenerateCSV(DataTable dt)
    {  
        StringBuilder sb = new StringBuilder();
        try
        {
            int count = 1;
            int totalColumns = dt.Columns.Count;
            foreach (DataColumn dr in dt.Columns)
            {
                sb.Append(dr.ColumnName);

                if (count != totalColumns)
                {
                    sb.Append(",");
                }

                count++;
            }

            sb.AppendLine();

            string value = String.Empty;
            foreach (DataRow dr in dt.Rows)
            {
                for (int x = 0; x < totalColumns; x++)
                {
                    value = dr[x].ToString();

                    if (value.Contains(",") || value.Contains("\""))
                    {
                        value = '"' + value.Replace("\"", "\"\"") + '"';
                    }

                    sb.Append(value);

                    if (x != (totalColumns - 1))
                    {
                        sb.Append(",");
                    }
                }

                sb.AppendLine();
            }
        }
        catch (Exception ex)
        {
            // Do something
        }
    }

3
此解决方案也在必要时检查和转义字符串,因此得到了赞同。 - Yogi
非常有用的答案。这个解决方案也考虑了转义字符。 - Brijesh Kumar Tripathi

3

我曾使用过这种方法,将对象数组复制到Excel单元格区域,而不是逐行逐列地复制,这证明是一种相当有效的方式。

    public void ExportToExcel(DataTable dataTable, String pathToSave)
    {
        // Create the Excel Application object
        var excelApp = new ApplicationClass();

        // Create a new Excel Workbook
        Workbook excelWorkbook = excelApp.Workbooks.Add(Type.Missing);

        int sheetIndex = 0;

        // Copy the DataTable to an object array
        var rawData = new object[dataTable.Rows.Count + 1, dataTable.Columns.Count];

        // Copy the column names to the first row of the object array
        for (var col = 0; col < dataTable.Columns.Count; col++)
        {
            rawData[0, col] = dataTable.Columns[col].ColumnName;
        }

        // Copy the values to the object array
        for (var col = 0; col < dataTable.Columns.Count; col++)
        {
            for (int row = 0; row < dataTable.Rows.Count; row++)
            {
                rawData[row + 1, col] = dataTable.Rows[row].ItemArray[col];
            }
        }

        // Calculate the final column letter
        string finalColLetter = string.Empty;
        const string colCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        int colCharsetLen = colCharset.Length;

        if (dataTable.Columns.Count > colCharsetLen)
        {
            finalColLetter = colCharset.Substring(
                (dataTable.Columns.Count - 1) / colCharsetLen - 1, 1);
        }

        finalColLetter += colCharset.Substring((dataTable.Columns.Count - 1) % colCharsetLen, 1);

        // Create a new Sheet
        var excelSheet = (Worksheet)excelWorkbook.Sheets.Add(excelWorkbook.Sheets.Item[++sheetIndex], Type.Missing, 1, XlSheetType.xlWorksheet);
        excelSheet.Name = dataTable.TableName;

        // Fast data export to Excel
        var excelRange = string.Format("A1:{0}{1}", finalColLetter, dataTable.Rows.Count + 1);
        excelSheet.Range[excelRange, Type.Missing].Value2 = rawData;

        // Mark the first row as BOLD and BLUE
        var headerColumnRange = (Range)excelSheet.Rows[1, Type.Missing];
        headerColumnRange.Font.Bold = true;
        headerColumnRange.Font.Color = 0xFF0000;
        headerColumnRange.EntireColumn.AutoFit();

        // Save and Close the Workbook
        excelWorkbook.SaveAs(pathToSave, XlFileFormat.xlWorkbookNormal, Type.Missing,
            Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlExclusive,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
        excelWorkbook.Close(true, Type.Missing, Type.Missing);
        excelWorkbook = null;

        // Release the Application object
        excelApp.Quit();
        excelApp = null;

        // Collect the unreferenced objects
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接