将对象列表转换为csv的最快方法,其中每个对象值都在新行中

Pas*_*mer 22 c# csv

我有一个课程如下:

public class Test
{
    public int Id {get;set;}
    public string Name { get; set; }
    public string CreatedDate {get;set;}
    public string DueDate { get; set; } 
    public string ReferenceNo { get; set; }       
    public string Parent { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我有一个Test对象列表

List<Test>testobjs=new List();
Run Code Online (Sandbox Code Playgroud)

现在我想以下列格式将其转换为csv:

"1,约翰格里沙姆,9/5/2014,9/5/2014,1356,0\N 2,斯蒂芬金,9/3/2014,9/9/2014,1367,0\N3,造雨,4/9/2014,18/9/2014,1" ;

我搜索了"将列表转换为csv c#",我得到的解决方案如下:

string.Join(",", list.Select(n => n.ToString()).ToArray())
Run Code Online (Sandbox Code Playgroud)

但是这不会根据需要放置\n,即每个对象

除了字符串构建之外还有其他最快的方法吗?请帮忙...

unr*_*eal 36

使用servicestack.text

Install-Package ServiceStack.Text
Run Code Online (Sandbox Code Playgroud)

然后使用字符串扩展方法 ToCsv(T)/FromCsv()

示例:https: //github.com/ServiceStack/ServiceStack.Text

更新: Servicestack.Text现在也是免费的v4曾经是商业版.无需再指定版本!快乐连载!

更新:ToCsv(T)/FromCsv()用于.NET Core.


小智 14

If you don't want to load library's than you can create the following method:

private void SaveToCsv<T>(List<T> reportData, string path)
{
    var lines = new List<string>();
    IEnumerable<PropertyDescriptor> props = TypeDescriptor.GetProperties(typeof(T)).OfType<PropertyDescriptor>();
    var header = string.Join(",", props.ToList().Select(x => x.Name));
    lines.Add(header);
    var valueLines = reportData.Select(row => string.Join(",", header.Split(',').Select(a => row.GetType().GetProperty(a).GetValue(row, null))));
    lines.AddRange(valueLines);
    File.WriteAllLines(path, lines.ToArray());
}
Run Code Online (Sandbox Code Playgroud)

and than call the method:

SaveToCsv(testobjs, "C:/PathYouLike/FileYouLike.csv")
Run Code Online (Sandbox Code Playgroud)


小智 13

因为在问题中提到了速度,我的兴趣被激发了相对表现可能是什么,以及我能够多快地得到它.

我知道StringBuilder被排除在外,但它仍然感觉可能是最快的,而StreamWriter当然具有写入MemoryStream或直接写入文件的优势,这使得它具有多种功能.

所以我敲了一个快速测试.

我建立了一个与你的相同的五十万个物品清单.

然后我使用CsvSerializer序列化,并使用两个手动滚动的紧密版本,一个使用StreamWriter到MemoryStream,另一个使用StringBuilder.

手动编码被编码以应对引号,但没有更复杂.这个代码非常紧凑,我可以管理中间字符串,没有连接...但不是生产,当然没有样式或灵活性的点.

但是在所有三种方法中输出都是相同的.

时间很有趣:

序列化50万个对象,每个方法运行5次,所有时间都到最近的整个mS:

StringBuilder     703     734     828     671     718   Avge=     730.8
MemoryStream      812     937     874     890     906   Avge=     883.8
CsvSerializer   1,734   1,469   1,719   1,593   1,578   Avge=   1,618.6
Run Code Online (Sandbox Code Playgroud)

这是一个高端的i7,有足够的RAM.

在其他条件相同的情况下,我总是会使用这个库.

但是,如果2:1的性能差异变得至关重要,或者RAM或其他问题变得夸大了较大数据集的差异,或者数据是以块的形式到达并且要直接发送到磁盘,我可能会受到诱惑...

为了防止任何人感兴趣,代码的核心(对于StringBuilder版本)是

    private void writeProperty(StringBuilder sb, string value, bool first, bool last)
    {
        if (! value.Contains('\"'))
        {
            if (!first)
                sb.Append(',');

            sb.Append(value);

            if (last)
                sb.AppendLine();
        }
        else
        {
            if (!first)
                sb.Append(",\"");
            else
                sb.Append('\"');

            sb.Append(value.Replace("\"", "\"\""));

            if (last)
                sb.AppendLine("\"");
            else
                sb.Append('\"');
        }
    }

    private void writeItem(StringBuilder sb, Test item)
    {
        writeProperty(sb, item.Id.ToString(), true, false);
        writeProperty(sb, item.Name, false, false);
        writeProperty(sb, item.CreatedDate, false, false);
        writeProperty(sb, item.DueDate, false, false);
        writeProperty(sb, item.ReferenceNo, false, false);
        writeProperty(sb, item.Parent, false, true);
    }
Run Code Online (Sandbox Code Playgroud)


AVe*_*Vee 5

您最好的选择是使用现有的库。它为您省去了自己弄清楚的麻烦,并且可能会处理转义特殊字符、添加标题行等。您可以使用ServiceStack 中的CSVSerializer。但是nuget中还有其他几个。创建 CSV 将变得如此简单string csv = CsvSerializer.SerializeToCsv(testobjs);