Как я могу преобразовать список объектов в CSV? - PullRequest
18 голосов
/ 21 февраля 2010

Если у меня есть список объектов под названием «Автомобиль»:

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

Как мне преобразовать список объектов, например, Список в csv?

Ответы [ 8 ]

14 голосов
/ 21 февраля 2010
  1. FileHelpers Библиотека
  2. Текстовый провайдер OleDb
  3. Ручное объединение строк в соответствии с RFC-4180
  4. Сторонняя библиотека, например Aspose.Cells может сделать это без каких-либо трений с вашей стороны. И это очень быстро.
9 голосов
/ 21 февраля 2010

добавить в 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);
}
8 голосов
/ 21 февраля 2010

Посмотрите на библиотеку 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 голосов
/ 03 февраля 2015

Я искал решение для этого, но ни один из найденных ответов не удовлетворил мое стремление к простоте. Я понял, что у меня был ответ уже с моим автоматическим кодом 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);

Вероятно, есть лучший способ написать эти два метода выше, но это отлично подходит для моей ситуации. Надеюсь, это кому-нибудь поможет.

1 голос
/ 10 ноября 2015

Вы можете просто переопределить метод 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());
            }
        }
0 голосов
/ 31 мая 2013

Другой вариант - Linq to CSV , пакет, доступный от NuGet. См. Объединение содержимого двух файлов с использованием LINQ to CSV для примера использования.

0 голосов
/ 21 февраля 2010

Я бы реализовал некоторые дополнительные методы сериализации согласно этой статье . Если вы хотите стать модным, вы можете создать настройку в свойствах ваших проектов. Этот параметр определит, использует ли ваш класс csv или сериализацию по умолчанию. Затем вы получите доступ к нему с помощью методов, показанных здесь . Подумайте об использовании статического конструктора для чтения настроек приложений и создания логического значения, доступного для вашего кода сериализации. Код 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
   {
   }
}

Это должно начать. , , Я не собирал и не проверял это. , но вы получите общее представление.

0 голосов
/ 21 февраля 2010

Собирая значения через запятую, я всегда хотел бы указать на очень недооцененный string.Join(string separator, string[] elements) статический метод, но если есть вспомогательные библиотеки, это, вероятно, лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...