You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WinForm中如何更快将DataTable导出为CSV文件?

优化DataTable导出CSV的性能方案

你的现有代码导出速度慢的核心原因是频繁的小IO操作(逐单元格调用StreamWriter.Write),以及缺乏字符串批量处理的优化。下面是几个更高效的实现方式,同时还会修复原代码未处理的CSV格式问题(比如字段包含逗号、引号时的格式错误):

方案1:使用StringBuilder批量构建内容+一次性写入

通过StringBuilder先拼接好所有行的内容,再一次性写入文件,大幅减少IO操作次数,提升速度:

public void CreateCSVFile(DataTable dtDataTablesList, string strFilePath)
{
    var sb = new StringBuilder();
    // 写入表头
    var headers = dtDataTablesList.Columns.Cast<DataColumn>()
                          .Select(col => EscapeCsvField(col.ColumnName));
    sb.AppendLine(string.Join(",", headers));

    // 写入数据行
    foreach (DataRow dr in dtDataTablesList.Rows)
    {
        var fields = dr.ItemArray.Select(item => 
        {
            if (Convert.IsDBNull(item))
                return string.Empty;
            return EscapeCsvField(item.ToString());
        });
        sb.AppendLine(string.Join(",", fields));
    }

    // 一次性写入文件
    File.WriteAllText(strFilePath, sb.ToString());
}

// 处理CSV字段的特殊字符(必须的,否则导出的CSV格式会出错)
private string EscapeCsvField(string field)
{
    if (field == null) return string.Empty;
    // 如果字段包含逗号、引号或换行符,需要用引号包裹,内部引号转义为双引号
    if (field.Contains(",") || field.Contains("\"") || field.Contains("\n") || field.Contains("\r"))
    {
        return $"\"{field.Replace("\"", "\"\"")}\"";
    }
    return field;
}

方案2:直接使用File.WriteAllLines(极简高效)

File.WriteAllLines内部做了IO优化,直接生成所有行的集合后一次性写入,代码更简洁:

public void CreateCSVFile(DataTable dtDataTablesList, string strFilePath)
{
    // 生成表头行
    var headerLine = string.Join(",", dtDataTablesList.Columns.Cast<DataColumn>()
                                                             .Select(col => EscapeCsvField(col.ColumnName)));
    // 生成数据行集合
    var dataLines = dtDataTablesList.Rows.Cast<DataRow>()
                                         .Select(dr => string.Join(",", dr.ItemArray.Select(item => 
                                         {
                                             if (Convert.IsDBNull(item))
                                                 return string.Empty;
                                             return EscapeCsvField(item.ToString());
                                         })));
    // 合并表头和数据行,一次性写入
    File.WriteAllLines(strFilePath, new[] { headerLine }.Concat(dataLines));
}

// 同样需要这个转义方法
private string EscapeCsvField(string field)
{
    if (field == null) return string.Empty;
    if (field.Contains(",") || field.Contains("\"") || field.Contains("\n") || field.Contains("\r"))
    {
        return $"\"{field.Replace("\"", "\"\"")}\"";
    }
    return field;
}

方案3:超大DataTable的异步处理(百万级行数)

如果你的DataTable包含几十万甚至上百万行,建议用异步写入避免阻塞主线程,同时用StreamWriter的异步方法配合批量写入:

public async Task CreateCSVFileAsync(DataTable dtDataTablesList, string strFilePath)
{
    using var sw = new StreamWriter(strFilePath, false);
    // 写入表头
    var headers = dtDataTablesList.Columns.Cast<DataColumn>()
                          .Select(col => EscapeCsvField(col.ColumnName));
    await sw.WriteLineAsync(string.Join(",", headers));

    // 批量写入数据行(比如每1000行一次)
    int batchSize = 1000;
    var batchSb = new StringBuilder();
    int count = 0;
    foreach (DataRow dr in dtDataTablesList.Rows)
    {
        var fields = dr.ItemArray.Select(item => 
        {
            if (Convert.IsDBNull(item))
                return string.Empty;
            return EscapeCsvField(item.ToString());
        });
        batchSb.AppendLine(string.Join(",", fields));
        count++;
        if (count % batchSize == 0)
        {
            await sw.WriteAsync(batchSb.ToString());
            batchSb.Clear();
        }
    }
    // 写入剩余的行
    if (batchSb.Length > 0)
    {
        await sw.WriteAsync(batchSb.ToString());
    }
}

// 转义方法同上
private string EscapeCsvField(string field)
{
    if (field == null) return string.Empty;
    if (field.Contains(",") || field.Contains("\"") || field.Contains("\n") || field.Contains("\r"))
    {
        return $"\"{field.Replace("\"", "\"\"")}\"";
    }
    return field;
}

为什么这些方案更快?

  1. 减少IO操作次数:原代码每次写单个单元格,会触发大量小IO;优化后的代码要么一次性写入所有内容,要么批量写入,IO次数大幅减少。
  2. 字符串拼接优化:StringBuilder比多次+拼接字符串的效率高得多,避免了大量临时字符串的创建。
  3. 格式正确性:新增的EscapeCsvField方法处理了CSV的特殊字符,不仅让导出的文件格式合规,也避免了因格式错误导致的潜在解析问题。

内容的提问来源于stack exchange,提问作者user5916500

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:55:17