2010-07-29 4 views
12

모든 클래스 인스턴스에서 CSV를 만드는 방법을 찾고 있습니다.CSV (일반 속성) 일반 클래스

내가 원하는 것은 모든 클래스 (모든 인스턴스)를 CSV로 내보낼 수 있다는 것입니다.

some1은 가능한 해결책을 제시 할 수 있습니까? (이미 answered 경우).

thanx!

+0

그래서 .. 그냥 쓰기? 직렬화 프로세스이지만 XML 또는 Binary 대신 CSV를 사용합니다. 무슨 문제 있니? –

+0

(a) 클래스에 대한 예제와 (b) 기대하는 CSV에 대한 예제를 제공하면 (a)에서 (b)로가는 방법에 대한 많은 답을 얻을 수 있습니다. –

+0

실키 : 나는 그것을 쓸 수는 있지만 클래스에 속성을 추가 할 때 CSV에 대해 걱정할 필요가없는 일반용이 필요합니다. Doc : 사용자 (이름, 성, 나이 ...와 같은 간단한 데이터 클래스) . 나는 ";"과 같은 것을 생각하고 있었다. 스타터를위한 헤더를 포함하여 구분됩니다. 단순한 클래스의 경우 – no9

답변

6

사실, 비슷한 여기에 해결되었습니다

Best practices for serializing objects to a custom string format for use in an output file

당신에게이 유용한가요?

리플렉션을 사용하여 필드 이름과 값을 빼내어 문자열에 추가하는 샘플이 있습니다.

+0

확장 메소드를 사용하지 않은 것 같습니다./ 정적 클래스를 만들었고 Hejndorf Per 메서드를 ost에 링크 된 메서드에 추가했습니다. 이제는 List <>에 메소드를 확장하는 방법을 모릅니다. 따라서 "User"클래스의 인스턴스를 포함하는 목록의 인스턴스에서 .ToCSV를 호출 할 수 있습니다. – no9

1

reflection을 사용하여 모든 클래스 속성/필드를 탐색하고이를 CSV에 쓸 수 있습니다. 더 나은 방법은 사용자 지정 특성을 정의하고 내보내려는 구성원을 꾸미고 해당 특성 만 내보내는 것입니다.

6

LINQ to CSV을 살펴보십시오. 그것은 무거운쪽에 조금 있지만, 내가 필요한 기능의 작은 하위 집합을 수행하기 위해 다음 코드를 작성한 이유입니다. 그것은 당신이 요청한 것처럼 속성과 필드를 모두 다루지 만 그리 많이는 아니지만. 한 가지는 쉼표, 따옴표 또는 개행 문자가 포함 된 경우 출력을 올바르게 이스케이프 처리하는 것입니다.

public static class CsvSerializer { 
    /// <summary> 
    /// Serialize objects to Comma Separated Value (CSV) format [1]. 
    /// 
    /// Rather than try to serialize arbitrarily complex types with this 
    /// function, it is better, given type A, to specify a new type, A'. 
    /// Have the constructor of A' accept an object of type A, then assign 
    /// the relevant values to appropriately named fields or properties on 
    /// the A' object. 
    /// 
    /// [1] http://tools.ietf.org/html/rfc4180 
    /// </summary> 
    public static void Serialize<T>(TextWriter output, IEnumerable<T> objects) { 
     var fields = 
      from mi in typeof (T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) 
      where new [] { MemberTypes.Field, MemberTypes.Property }.Contains(mi.MemberType) 
      let orderAttr = (ColumnOrderAttribute) Attribute.GetCustomAttribute(mi, typeof (ColumnOrderAttribute)) 
      orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name 
      select mi; 
     output.WriteLine(QuoteRecord(fields.Select(f => f.Name))); 
     foreach (var record in objects) { 
      output.WriteLine(QuoteRecord(FormatObject(fields, record))); 
     } 
    } 

    static IEnumerable<string> FormatObject<T>(IEnumerable<MemberInfo> fields, T record) { 
     foreach (var field in fields) { 
      if (field is FieldInfo) { 
       var fi = (FieldInfo) field; 
       yield return Convert.ToString(fi.GetValue(record)); 
      } else if (field is PropertyInfo) { 
       var pi = (PropertyInfo) field; 
       yield return Convert.ToString(pi.GetValue(record, null)); 
      } else { 
       throw new Exception("Unhandled case."); 
      } 
     } 
    } 

    const string CsvSeparator = ","; 

    static string QuoteRecord(IEnumerable<string> record) { 
     return String.Join(CsvSeparator, record.Select(field => QuoteField(field)).ToArray()); 
    } 

    static string QuoteField(string field) { 
     if (String.IsNullOrEmpty(field)) { 
      return "\"\""; 
     } else if (field.Contains(CsvSeparator) || field.Contains("\"") || field.Contains("\r") || field.Contains("\n")) { 
      return String.Format("\"{0}\"", field.Replace("\"", "\"\"")); 
     } else { 
      return field; 
     } 
    } 

    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 
    public class ColumnOrderAttribute : Attribute { 
     public int Order { get; private set; } 
     public ColumnOrderAttribute(int order) { Order = order; } 
    } 
} 
0

나는 두 개의 섹션으로 내 대답을 분리하고 : 를 첫 번째 인코딩, 헤더, CSV로 몇 가지 일반적인 항목 목록을 내보내는 방법입니다 - (그것은 단지 지정 헤더에 대한 CSV 데이터를 구축 할 것이며, 무시 불필요한 속성).

public string ExportCsv<T>(IEnumerable<T> items, Dictionary<string, string> headers) 
{ 
    string result; 
    using (TextWriter textWriter = new StreamWriter(myStream, myEncoding)) 
    { 
     result = this.WriteDataAsCsvWriter<T>(items, textWriter, headers); 
    } 
    return result; 
} 

private string WriteDataAsCsvWriter<T>(IEnumerable<T> items, TextWriter textWriter, Dictionary<string, string> headers) 
{ 
    //Add null validation 

    ////print the columns headers 
    StringBuilder sb = new StringBuilder(); 

    //Headers 
    foreach (KeyValuePair<string, string> kvp in headers) 
    { 
     sb.Append(ToCsv(kvp.Value)); 
     sb.Append(","); 
    } 
    sb.Remove(sb.Length - 1, 1);//the last ',' 
    sb.Append(Environment.NewLine); 

    //the values 
    foreach (var item in items) 
    { 
     try 
     { 
      Dictionary<string, string> values = GetPropertiesValues(item, headers); 

      foreach (var value in values) 
      { 
       sb.Append(ToCsv(value.Value)); 
       sb.Append(","); 
      } 
      sb.Remove(sb.Length - 1, 1);//the last ',' 
      sb.Append(Environment.NewLine); 
     } 
     catch (Exception e1) 
     { 
      //do something 
     } 
    } 
    textWriter.Write(sb.ToString()); 

    return sb.ToString(); 
} 

//Help function that encode text to csv: 
public static string ToCsv(string input) 
{ 
    if (input != null) 
    { 
     input = input.Replace("\r\n", string.Empty) 
      .Replace("\r", string.Empty) 
      .Replace("\n", string.Empty); 
     if (input.Contains("\"")) 
     { 
      input = input.Replace("\"", "\"\""); 
     } 

     input = "\"" + input + "\""; 
    } 

    return input; 
} 

이것은 가장 중요한 기능으로, (거의) 모든 일반 클래스에서 속성 값을 추출합니다. GetPropertiesValues에 대한

private Dictionary<string, string> GetPropertiesValues(object item, Dictionary<string, string> headers) 
{ 
    Dictionary<string, string> values = new Dictionary<string, string>(); 
    if (item == null) 
    { 
     return values; 
    } 

    //We need to make sure each value is coordinated with the headers, empty string 
    foreach (var key in headers.Keys) 
    { 
     values[key] = String.Empty; 
    } 

    Type t = item.GetType(); 
    PropertyInfo[] propertiesInfo = t.GetProperties(); 

    foreach (PropertyInfo propertiyInfo in propertiesInfo) 
    { 
     //it not complex: string, int, bool, Enum 
     if ((propertiyInfo.PropertyType.Module.ScopeName == "CommonLanguageRuntimeLibrary") || propertiyInfo.PropertyType.IsEnum) 
     { 
      if (headers.ContainsKey(propertiyInfo.Name)) 
      { 
       var value = propertiyInfo.GetValue(item, null); 
       if (value != null) 
       { 
        values[propertiyInfo.Name] = value.ToString(); 
       }       
      } 
     } 
     else//It's complex property 
     { 
      if (propertiyInfo.GetIndexParameters().Length == 0) 
      { 
       Dictionary<string, string> lst = GetPropertiesValues(propertiyInfo.GetValue(item, null), headers); 
       foreach (var value in lst) 
       { 
        if (!string.IsNullOrEmpty(value.Value)) 
        { 
         values[value.Key] = value.Value; 
        } 
       } 
      } 
     } 
    } 
    return values; 
} 

예 :

public MyClass 
{ 
    public string Name {get; set;} 
    public MyEnum Type {get; set;} 
    public MyClass2 Child {get; set;} 
} 
public MyClass2 
{ 
    public int Age {get; set;} 
    public DateTime MyDate {get; set;} 
} 

MyClass myClass = new MyClass() 
{ 
    Name = "Bruce", 
    Type = MyEnum.Sometype, 
    Child = new MyClass2() 
    { 
     Age = 18, 
     MyDate = DateTime.Now() 
    } 
}; 

Dictionary<string, string> headers = new Dictionary<string, string>(); 
headers.Add("Name", "CustomCaption_Name"); 
headers.Add("Type", "CustomCaption_Type"); 
headers.Add("Age", "CustomCaption_Age"); 

GetPropertiesValues(myClass, headers)); // OUTPUT: {{"Name","Bruce"},{"Type","Sometype"},{"Age","18"}}