2010-02-21 22 views
18

Jeśli mam listę obiektów zwanych „samochodów”:Jak przekonwertować listę obiektów na CSV?

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

Jak przekonwertować listę obiektów, na przykład List < Samochód > do pliku CSV?

+0

Czy jesteś w stanie to zrobić? Którego próbowałeś? – Praveen

Odpowiedz

14
  1. FileHelpers Biblioteka
  2. OleDb Tekst Provider
  3. Instrukcja poprzez łączenie String według RFC-4180
  4. biblioteki strony trzeciej, na przykład Aspose.Cells może to zrobić bez żadnego tarcia od ciebie. I to jest bardzo szybkie uzyskanie bardzo.
+1

+1 za link do RFC! Jest też dobre odniesienie do Wikipedii: http://en.wikipedia.org/wiki/Comma-separated_values – TrueWill

8

Spójrz na bibliotekę FileHelpers.

Z witryny:

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.

To będzie upewnić się, że wszystkie rodzaje pułapek w rozwiązaniu linia, ucieczki i takie są obsługiwane poprawnie, zgodnie RFC-4180.

0

Łączenie wartości rozdzielanych przecinkami Zawsze lubię wskazywać na bardzo niedocenianą metodę statyczną string.Join(string separator, string[] elements), ale jeśli są tam biblioteki pomocnicze, to prawdopodobnie lepsze rzeczy.

8

dodaj następującą metodę 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"); 
} 

Teraz można szeregować całą listę:

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

chciałbym wdrożyć pewne addtional zachowań serialzation jak na tym article. Jeśli chcesz mieć ochotę, możesz utworzyć ustawienie we właściwościach projektu. To ustawienie określa, czy twoja klasa używała csv lub domyślnej szeregowania. Dostęp do nich byłby możliwy dzięki wyświetlanym technikom: here. Rozważ użycie statycznego konstruktora do odczytu ustawień i uzyskania wartości boolowskiej dostępnej do kodu serializacji. Kod Vlada wygląda świetnie, po prostu podłącz go do swojego kodu. Możesz także rozważyć inne, być może bardziej pożądane sposoby zmiany zachowania podczas seryjności.

Lub Utwórz interfejs o nazwie 'SerializeAsCSV' i używać go niby tak:

// część zawartości 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 
     } 

    } 

// zawartość ISerializeAsCSV.cs

using System.Runtime.Serialization; 

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

To powinno wystartować. . . Nie skompilowałem tego i nie przetestowałem tego. . ale masz ogólny pomysł.

3

Szukałem rozwiązania tego problemu, ale żadna z odpowiedzi, które znalazłem, nie zaspokajała mojej motywacji do prostoty. Zdałem sobie sprawę, że mam już odpowiedź z mojego automatycznego kodu CRUD. I repurposed go i wpadł na następujący kod:

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); 
    } 

Byłoby dodać metodę rozszerzenia do każdego obiektu. Sposób użycia:

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); 

Prawdopodobnie jest lepszy sposób na zapisanie tych dwóch metod powyżej, ale działa to idealnie w mojej sytuacji. Mam nadzieję, że to komuś pomaga.

1

Można po prostu zastąpić metodę ToString lub utworzyć metodę ToCSVRow() jako takiego

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

A potem po prostu zrobić coś takiego, gdzie potrzebne.

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