如何将对象列表转换为csv?

时间:2010-02-21 17:19:04

标签: c# linq list csv generics

如果我有一个名为“Car”的对象列表:

public class Car
{
     public string Name;
     public int Year;
     public string Model;
}

如何转换对象列表,例如列表与LT;汽车和GT;到csv?

8 个答案:

答案 0 :(得分:14)

  1. FileHelpers图书馆
  2. 文字OleDb提供商
  3. 根据RFC-4180
  4. 手动进行字符串连接
  5. 第三方库,例如Aspose.Cells可以在没有任何摩擦的情况下执行此操作。并且非常快。

答案 1 :(得分:9)

将以下方法添加到Car:

String Escape(String s)
{
    StringBuilder sb = new StringBuilder();
    bool needQuotes = false;
    foreach (char c in s.ToArray())
    {
        switch (c)
        {
            case '"': sb.Append("\\\""); needQuotes = true; break;
            case ' ': sb.Append(" "); needQuotes = true; break;
            case ',': sb.Append(","); needQuotes = true; break;
            case '\t': sb.Append("\\t"); needQuotes = true; break;
            case '\n': sb.Append("\\n"); needQuotes = true; break;
            default: sb.Append(c); break;
        }
    }
    if (needQuotes)
        return "\"" + sb.ToString() + "\"";
    else
        return sb.ToString();
}

public void SerializeAsCsv(Stream stream)
{
    stream.Write(Escape(Name));
    stream.Write(",");
    stream.Write(Year.ToString());
    stream.Write(",");
    stream.Write(Escape(Model));
    stream.Write("\n");
}

现在您可以序列化整个列表:

foreach (Car car in list)
{
    car.SerializeAsCsv(stream);
}

答案 2 :(得分:8)

查看FileHelpers库。

来自网站:

The FileHelpers are a free and easy to use .NET library to import/export data from fixed length or delimited records in files, strings or streams.

这将确保按行RFC-4180正确处理行终止,转义等所有类型的陷阱。

答案 3 :(得分:3)

我正在寻找一个解决方案,但我找到的答案都没有满足我的简单性。我意识到我的自动CRUD代码已经有了答案。我重新调整它并提出以下代码:

using System.Reflection;
    /// <summary>
    /// Using a bit of reflection to build up the strings.
    /// </summary>
    public static string ToCsvHeader(this object obj)
    {
        Type type = obj.GetType();
        var properties = type.GetProperties(BindingFlags.DeclaredOnly |
                                       BindingFlags.Public |
                                       BindingFlags.Instance);

        string result = string.Empty;
        Array.ForEach(properties, prop =>
        {
            result += prop.Name + ",";
        });

        return (!string.IsNullOrEmpty(result) ? result.Substring(0, result.Length - 1) : result);
    }

    public static string ToCsvRow(this object obj)
    {
        Type type = obj.GetType();
        var properties = type.GetProperties(BindingFlags.DeclaredOnly |
                                       BindingFlags.Public |
                                       BindingFlags.Instance);

        string result = string.Empty;
        Array.ForEach(properties, prop =>
        {
            var value = prop.GetValue(obj, null);
            var propertyType = prop.PropertyType.FullName;
            if (propertyType == "System.String")
            {
                // wrap value incase of commas
                value = "\"" + value + "\"";
            }

            result += value + ",";

        });

        return (!string.IsNullOrEmpty(result) ? result.Substring(0, result.Length - 1) : result);
    }

这将为每个对象添加扩展方法。用法如下:

var burgers = new List<Cheeseburger>();
var output = burgers.ToCsvHeader();
output += Environment.NewLine;

burgers.ForEach(burger =>
{
    output += burger.ToCsvRow();
    output += Environment.NewLine;
});
var path = "[where ever you want]";
System.IO.File.WriteAllText(path, output);

上面写这两种方法可能有更好的方法,但这对我的情况很有效。希望它可以帮到某人。

答案 4 :(得分:1)

您可以简单地覆盖ToString方法或创建ToCSVRow()方法

    public String ToCSVRow()
    {
        return Name + "," + Year.ToString() + "," + Model;
    }

然后在需要的地方做这样的事情。

    using (StreamWriter file = new StreamWriter(@"C:\Wherever\yourfilename.txt"))
        {
            foreach (var item in yourlist)
            {
                file.WriteLine(item.ToCSVRow());
            }
        }

答案 5 :(得分:0)

将逗号分隔的值放在一起我总是喜欢指向被低估的string.Join(string separator, string[] elements)静态方法,但如果有辅助库,那可能是更好的东西。

答案 6 :(得分:0)

我按照article实现了一些额外的序列化行为。如果您想获得幻想,可以在项目属性中创建一个设置。此设置将确定您的类是使用csv还是默认的序列化。然后,您可以通过here显示的技术访问它。考虑使用静态构造函数来读取appsettings并使一个布尔值可以访问序列化代码。 Vlads的代码看起来很棒,只需将其插入代码即可。此外,您还可以考虑其他更好的方法来改变序列化行为。

或者创建一个名为“SerializeAsCSV”的接口,并使用它类似:

// MyCoolClass.csv的部分内容:

   public class MyCoolClass : ISerializeAsCSV, IDisposable
   {

      protected static bool serializesToCSV = false;


      static MyCoolClass()
      {
         serializesToCSV = 
            (typeof(MyCoolClass).GetInterface("GrooveySoft.Shared.Interfaces.ISerializeAsCSV") == null)
            ? false
            : true;

      }


      public MyCoolClass(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
      {
        // your stuff here
      }

      public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
      {
         // your stuff here
      }

    }

// ISerializeAsCSV.cs的内容

using System.Runtime.Serialization;

namespace GrooveySoft.Shared.Interfaces
{
   /// <summary>
   /// indicates that implementor will serialize to csv format
   /// </summary>
   public interface ISerializeAsCSV : ISerializable
   {
   }
}

这应该让你开始。 。 。我没有编译和测试过这个。 。但你得到了一般的想法。

答案 7 :(得分:0)

另一个选项是Linq to CSV,这是NuGet提供的一个软件包。有关示例用法,请参阅Combine contents of two files using LINQ to CSV