数据表格转换为CSV文件

5

这个问题与解析CSV无关。

使用以下代码从DataTable创建CSV,但速度很慢。
100行14列需要4秒钟。
有更快的方法吗?

StringBuilder sb = new StringBuilder();
bool first = true;
int colCount = 0;
foreach (DataColumn dc in DT.Columns)
{
    if (first) first = false; else sb.Append(",");
    sb.Append("\"" + dc.ColumnName +  "\"");
    colCount++;
}
sb.AppendLine();
foreach (DataRow dr in DT.Rows)
{  
    first = true;
    for (int i = 0; i < colCount; i++)
    {
        if (first) first = false; else sb.Append(",");
        sb.Append("\"" + dr[i].ToString().Trim() + "\"");
    }
    sb.AppendLine();
}
return sb.ToString();

StringBuilder在这里不是问题。
将i从0加载到1000000,在300毫秒内完成。

StringBuilder sb = new StringBuilder();
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000000; i++)
{
    sb.Append(i.ToString());
}
sw.Stop();
Debug.Write(sw.ElapsedMilliseconds.ToString());

1
@DourHighArch 这个问题是关于创建CSV文件,而不是解析CSV文件。这个问题中没有任何关于解析CSV文件的内容。 - paparazzo
1
我的唯一评论是,你将输出写入了一个 StringBuilder 中 - 为什么不直接写入流中呢? - Matt
1
不,从CPU层面来看,这两者的复杂度是等价的。 - 500 - Internal Server Error
抱歉 @Blam,我误解了你的问题。你可以删除提出的答案,或将其保留作为警示给那些可能没有正确阅读问题的人。 - Dour High Arch
1
我还没有给你答案,但是我编写了一些代码并且在datatable方面没有发现任何问题。你确定你的DataTable是真正的问题,而不是应用程序中的其他东西使CPU/IO达到最大值,从而没有给你的代码足够的运行机会吗?我做的示例在这里https://gist.github.com/PaulFarry/6e5e1e80f484cfad1218 - Paul Farry
显示剩余7条评论
2个回答

11

有更快的字符串连接和其他逻辑实现方式。使用字符串构建器来构建整个内容可能也是减速的一部分。一些库已经考虑了这些问题,可能会更快,正如一些人建议的那样。

这里有一些使用CsvHelper的代码(由我编写)。

using( var dt = new DataTable() )
{
    dt.Load( dataReader );
    foreach( DataColumn column in dt.Columns )
    {
        csv.WriteField( column.ColumnName );
    }
    csv.NextRecord();

    foreach( DataRow row in dt.Rows )
    {
        for( var i = 0; i < dt.Columns.Count; i++ )
        {
            csv.WriteField( row[i] );
        }
        csv.NextRecord();
    }
}
如果您有DataReader,那么甚至不需要使用DataTable,这样应该能加速一些。
var hasHeaderBeenWritten = false;
while( dataReader.Read() )
{
    if( !hasHeaderBeenWritten )
    {
        for( var i = 0; i < dataReader.FieldCount; i++ )
        {
            csv.WriteField( dataReader.GetName( i ) );
        }
        csv.NextRecord();
        hasHeaderBeenWritten = true;
    }

    for( var i = 0; i < dataReader.FieldCount; i++ )
    {
        csv.WriteField( dataReader[i] );
    }
    csv.NextRecord();
}

3
感谢提供示例,其中缺少using (var csv = new CsvWriter(writer))部分,这可能会让一些人感到困惑。 - codeulike

-2

你那里的代码并不是“很好”的代码...我认为大多数人会建议使用类似于CSVHelper NuGet包的东西。然而,我也要说,仅有100行的情况下,那段代码不是花费4秒钟的原因。获取数据表中的数据需要多长时间?我猜这就是花费4秒钟大部分时间的地方。


4秒钟是从现有的DataTable中提取文本的时间,而不是创建DataTable的时间。并向我展示CSVHelper如何读取DataTable。 - paparazzo

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