2009-12-11 9 views
108

मैं पूर्णांक मूल्यों (सूची) की एक सूची है और अल्पविराम से परे मूल्यों की एक स्ट्रिंग उत्पन्न करने के लिए चाहते हैं के लिए एक क्रियाशील सूची परिवर्तित। सूची आउटपुट में यह एक ही कॉमा सीमांकित सूची में सभी आइटम है।एक सीएसवी स्ट्रिंग

मेरे विचार ... 1. एक पद्धति के लिए सूची गुजरती हैं। 2. stringbuilder सूची पुनरावृति और अल्पविराम के 3. टेस्ट अंतिम वर्ण संलग्न करें और अगर यह एक अल्पविराम है, उसे हटाने के लिए।

आपके क्या विचार हैं? क्या यह सबसे अच्छा तरीका है?

कैसे मेरे कोड परिवर्तन अगर मैं न केवल पूर्णांकों (अपने वर्तमान प्लान), लेकिन तार, देशांतर, संभाल करने के लिए चाहता था डबल्स होगा, bools, आदि, भविष्य में आदि? मुझे लगता है कि यह किसी भी प्रकार की सूची स्वीकार करता है।

उत्तर

189

यह क्या फ्रेमवर्क पहले से ही हमारे लिए करता है अद्भुत है।

List<int> myValues; 
string csv = String.Join(",", myValues.Select(x => x.ToString()).ToArray()); 

सामान्य स्थिति के लिए:

IEnumerable<T> myList; 
string csv = String.Join(",", myList.Select(x => x.ToString()).ToArray()); 

आप देख सकते हैं, यह प्रभावी रूप से अलग नहीं है। खबरदार कि आप वास्तव में उद्धरण में x.ToString() (अर्थात, "\"" + x.ToString() + "\"") मामले x.ToString() में अल्पविराम शामिल रैप करने के लिए आवश्यकता हो सकती है।

इस के एक मामूली संस्करण पर एक दिलचस्प पढ़ने के लिए: एरिक Lippert के ब्लॉग पर Comma Quibbling देखते हैं।

नोट: यह लिखा गया था .NET 4.0 से पहले आधिकारिक तौर पर जारी किया गया था। अब हम केवल

IEnumerable<T> sequence; 
string csv = String.Join(",", sequence); 

अधिभार String.Join<T>(string, IEnumerable<T>) का उपयोग कर सकते हैं। यह विधि प्रत्येक तत्व x से x.ToString() पर स्वचालित रूप से प्रोजेक्ट करेगी।

+0

'सूची ' जब तक मैं कुछ याद आ रही है ढांचा 3.5 में विधि 'Select' जरूरत नहीं है। – ajeh

+2

@ajeh: आप शायद 'उपयोग' कथन खो रहे हैं। – jason

+0

कौन सा विशिष्ट आयात? – ajeh

7

आप String.Join उपयोग कर सकते हैं। ,

string commaSeparated = myList.JoinStrings(", "); 
+0

यहां 'कनवर्टअल' पर कॉल में जेनेरिक टाइप पैरामीटर निर्दिष्ट करने की आवश्यकता नहीं है - दोनों 'int' और 'string' का अनुमान लगाया जाएगा। –

+0

टिप के लिए धन्यवाद। –

+1

'Array.ConvertAll (... 'करने के बजाय आप केवल' सूची कर सकते हैं। ConvertAll (e => e.ToString())। ToArray) ', बस कम टाइपिंग। – David

10

आप एक विस्तार विधि कि आप किसी भी IEnumerable पर कॉल कर सकते हैं बना सकते हैं मैं अभी भी ऐसा करने में सक्षम था। यह बहुत आसान है और लैम्ब्डा की जरूरत नहीं है।

String.Join(",", myList.ToArray<string>()); 
10
3,5 में

:

public static string JoinStrings<T>(
    this IEnumerable<T> values, string separator) 
{ 
    var stringValues = values.Select(item => 
     (item == null ? string.Empty : item.ToString())); 
    return string.Join(separator, stringValues.ToArray()); 
} 

तो फिर तुम सिर्फ मूल सूची में विधि कॉल कर सकते हैं:

String.Join(
    ",", 
    Array.ConvertAll(
    list.ToArray(), 
    element => element.ToString() 
) 
); 
+0

'सूची ' की 'ToArray() 'विधि का उपयोग फ्रेमवर्क 3.5 में टाइप तर्क के साथ नहीं किया जा सकता है जब तक कि मुझे कुछ याद नहीं आ रहा है। – ajeh

3

कोई समाधान काम केवल सूची अगर एक (स्ट्रिंग की) सूची

आप (कार के) जहां कार n गुण है, तो आप पाश PropertiesInfo चाहिए सूची की तरह अपने स्वयं के वस्तुओं की एक सामान्य सूची है प्रत्येक कार वस्तु का।

देखो पर: http://www.csharptocsharp.com/generate-csv-from-generic-list

+1

क्या आप कक्षा के ToString को ओवरराइड नहीं कर सकते हैं और उपरोक्त विधियों का उपयोग नहीं कर सकते? –

5

शरीर के किसी भी कस्टम वर्ग की सूचीके बजाय स्ट्रिंग की सूची वस्तुओं फिर अपने वर्ग का csv पंक्ति प्रतिनिधित्व के साथ अपने वर्ग के ToString विधि ओवरराइड कन्वर्ट करने के लिए चाहता है।

Public Class MyClass{ 
    public int Id{get;set;} 
    public String PropertyA{get;set;} 
    public override string ToString() 
    { 
    return this.Id+ "," + this.PropertyA; 
    } 
} 

तो कोड के बाद एक छोटे से मुद्दे था हैडर कॉलम

string csvHeaderRow = String.Join(",", typeof(MyClass).GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(x => x.Name).ToArray<string>()) + Environment.NewLine; 
string csv= csvHeaderRow + String.Join(Environment.NewLine, MyClass.Select(x => x.ToString()).ToArray()); 
4

@Frank Create a CSV File from a .NET Generic List द्वारा दिए गए लिंक में कोड के रूप में साथ सीएसवी को यह कक्षा सूची कन्वर्ट करने के लिए इस्तेमाल किया जा सकता , के साथ हर पंक्ति को समाप्त करने के लिए मैंने इसे छुटकारा पाने के लिए कोड को संशोधित किया। उम्मीद है कि यह किसी की मदद करे।

string CsvString = myList.ToCsv(); 

क्लीनर और आसान अन्य की तुलना में पढ़ने के लिए:

/// <summary> 
/// Creates the CSV from a generic list. 
/// </summary>; 
/// <typeparam name="T"></typeparam>; 
/// <param name="list">The list.</param>; 
/// <param name="csvNameWithExt">Name of CSV (w/ path) w/ file ext.</param>; 
public static void CreateCSVFromGenericList<T>(List<T> list, string csvCompletePath) 
{ 
    if (list == null || list.Count == 0) return; 

    //get type from 0th member 
    Type t = list[0].GetType(); 
    string newLine = Environment.NewLine; 

    if (!Directory.Exists(Path.GetDirectoryName(csvCompletePath))) Directory.CreateDirectory(Path.GetDirectoryName(csvCompletePath)); 

    if (!File.Exists(csvCompletePath)) File.Create(csvCompletePath); 

    using (var sw = new StreamWriter(csvCompletePath)) 
    { 
     //make a new instance of the class name we figured out to get its props 
     object o = Activator.CreateInstance(t); 
     //gets all properties 
     PropertyInfo[] props = o.GetType().GetProperties(); 

     //foreach of the properties in class above, write out properties 
     //this is the header row 
     sw.Write(string.Join(",", props.Select(d => d.Name).ToArray()) + newLine); 

     //this acts as datarow 
     foreach (T item in list) 
     { 
      //this acts as datacolumn 
      var row = string.Join(",", props.Select(d => item.GetType() 
                  .GetProperty(d.Name) 
                  .GetValue(item, null) 
                  .ToString()) 
                .ToArray()); 
      sw.Write(row + newLine); 

     } 
    } 
} 
+0

अतिरिक्त जानकारी: प्रक्रिया फ़ाइल 'c: \ temp \ matchingMainWav.csv' तक नहीं पहुंच सकती है क्योंकि इसका उपयोग किसी अन्य प्रक्रिया द्वारा किया जा रहा है। फ़ोल्डर 'देव' मौजूद है, लेकिन फ़ाइल नहीं ... क्या मैं उस अधिकार का उपयोग नहीं कर रहा हूं? –

+0

फ़ाइल। क्रिएट विधि फ़ाइल बनाता है और फ़ाइल पर एक फ़ाइलस्ट्रीम खोलता है। तो आपकी फाइल पहले से ही खुली है। आपको वास्तव में फ़ाइल की आवश्यकता नहीं है। विधि बनाएं: – David

3

मैं एक अच्छा सरल विस्तार विधि

public static string ToCsv(this List<string> itemList) 
     { 
      return string.Join(",", itemList); 
     } 

तो फिर तुम सिर्फ मूल सूची में विधि कॉल कर सकते हैं सुझाव।

0

http://cc.davelozinski.com/c-sharp/the-fastest-way-to-read-and-process-text-files

इस वेबसाइट कैसे, बफ़र लेखक का उपयोग कर लाइन द्वारा लाइन पढ़ने को एक फ़ाइल में लिखने के बारे में कुछ व्यापक परीक्षण का सबसे अच्छा तरीका हो रहा है था, स्ट्रिंग निर्माता का उपयोग करके धीरे से एक था।

मैं अपनी तकनीक का उपयोग करने के लिए सामान लिखने के लिए एक बड़ा सौदा करता हूं, यह अच्छी तरह से काम करता है।

0

स्ट्रिंग.जॉइन के साथ समस्या यह है कि आप मान में पहले से मौजूद अल्पविराम का मामला नहीं संभाले हैं। जब एक अल्पविराम मौजूद होता है तो आप उद्धरणों में मूल्य को घेरते हैं और सभी मौजूदा उद्धरणों को डबल कोट्स के साथ प्रतिस्थापित करते हैं।

String.Join(",",{"this value has a , in it","This one doesn't", "This one , does"}); 

CSV Module

2

मैं इस post में में गहराई से समझा देखें। मैं संक्षिप्त विवरण के साथ यहां कोड पेस्ट कर दूंगा।

यहां विधि है जो हेडर पंक्ति बनाता है। यह संपत्ति नामों को स्तंभ नाम के रूप में उपयोग करता है।

private static void CreateHeader<T>(List<T> list, StreamWriter sw) 
    { 
     PropertyInfo[] properties = typeof(T).GetProperties(); 
     for (int i = 0; i < properties.Length - 1; i++) 
     { 
      sw.Write(properties[i].Name + ","); 
     } 
     var lastProp = properties[properties.Length - 1].Name; 
     sw.Write(lastProp + sw.NewLine); 
    } 

इस विधि सभी मूल्य पंक्तियों

private static void CreateRows<T>(List<T> list, StreamWriter sw) 
    { 
     foreach (var item in list) 
     { 
      PropertyInfo[] properties = typeof(T).GetProperties(); 
      for (int i = 0; i < properties.Length - 1; i++) 
      { 
       var prop = properties[i]; 
       sw.Write(prop.GetValue(item) + ","); 
      } 
      var lastProp = properties[properties.Length - 1]; 
      sw.Write(lastProp.GetValue(item) + sw.NewLine); 
     } 
    } 

बनाता है और यहाँ विधि है कि उन्हें एक साथ लाता है और वास्तविक फ़ाइल बनाता है।

public static void CreateCSV<T>(List<T> list, string filePath) 
    { 
     using (StreamWriter sw = new StreamWriter(filePath)) 
     { 
      CreateHeader(list, sw); 
      CreateRows(list, sw); 
     } 
    } 
+1

यह बहुत अच्छी तरह से काम करता है। मैंने पैरामीटर के रूप में डिलीमीटर को पास करने के लिए इसे बेहतर बनाया है, इसलिए किसी भी प्रकार की सीमांकित फ़ाइल उत्पन्न की जा सकती है। सीएसवी के साथ सौदा करने के लिए दर्द होता है यदि पाठ में अल्पविराम होता है, इसलिए मैं बेहतर संस्करण का उपयोग करके '|' सीमांकित फाइलें उत्पन्न करता हूं। धन्यवाद! – Shiva

1

सीएसवीहेल्पर पुस्तकालय Nuget में बहुत लोकप्रिय है। आप इसके लायक हैं, आदमी! https://github.com/JoshClose/CsvHelper/wiki/Basics

सीएसवीहेल्पर का उपयोग करना वास्तव में आसान है। यह डिफ़ॉल्ट सेटिंग्स सबसे आम परिदृश्यों के लिए सेटअप हैं।

यहां एक छोटा सेटअप डेटा है।

Actors.csv:

Id,FirstName,LastName 
1,Arnold,Schwarzenegger 
2,Matt,Damon 
3,Christian,Bale 

अभिनेता।सीएस (कस्टम वर्ग उद्देश्य यह है कि एक अभिनेता का प्रतिनिधित्व करता है):

public class Actor 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

CsvReader का उपयोग कर CSV फ़ाइल पढ़ना:

var csv = new CsvReader(new StreamReader("Actors.csv")); 

वर actorsList = csv.GetRecords();

एक CSV फ़ाइल को लिखना।

using (var csv = new CsvWriter(new StreamWriter("Actors.csv"))) 
{ 
    csv.WriteRecords(actorsList); 
} 
0

एक सामान्य प्रयोजन ToCsv() विस्तार विधि:

  • का समर्थन करता है int16/32/64, नाव, डबल, दशमलव, और कुछ भी ToString समर्थन()
  • वैकल्पिक कस्टम विभाजक में शामिल होने के
  • वैकल्पिक कस्टम चयनकर्ता
  • वैकल्पिक शून्य/खाली हैंडलिंग विनिर्देश (* ऑप्ट() अधिभार)

प्रयोग उदाहरण:

"123".ToCsv() // "1,2,3" 
"123".ToCsv(", ") // "1, 2, 3" 
new List<int> { 1, 2, 3 }.ToCsv() // "1,2,3" 

new List<Tuple<int, string>> 
{ 
    Tuple.Create(1, "One"), 
    Tuple.Create(2, "Two") 
} 
.ToCsv(t => t.Item2); // "One,Two" 

((string)null).ToCsv() // throws exception 
((string)null).ToCsvOpt() // "" 
((string)null).ToCsvOpt(ReturnNullCsv.WhenNull) // null 

कार्यान्वयन

/// <summary> 
/// Specifies when ToCsv() should return null. Refer to ToCsv() for IEnumerable[T] 
/// </summary> 
public enum ReturnNullCsv 
{ 
    /// <summary> 
    /// Return String.Empty when the input list is null or empty. 
    /// </summary> 
    Never, 

    /// <summary> 
    /// Return null only if input list is null. Return String.Empty if list is empty. 
    /// </summary> 
    WhenNull, 

    /// <summary> 
    /// Return null when the input list is null or empty 
    /// </summary> 
    WhenNullOrEmpty, 

    /// <summary> 
    /// Throw if the argument is null 
    /// </summary> 
    ThrowIfNull 
} 

/// <summary> 
/// Converts IEnumerable list of values to a comma separated string values. 
/// </summary> 
/// <typeparam name="T"></typeparam> 
/// <param name="values">The values.</param>   
/// <param name="joinSeparator"></param> 
/// <returns>System.String.</returns> 
public static string ToCsv<T>(
    this IEnumerable<T> values,    
    string joinSeparator = ",") 
{ 
    return ToCsvOpt<T>(values, null /*selector*/, ReturnNullCsv.ThrowIfNull, joinSeparator); 
} 

/// <summary> 
/// Converts IEnumerable list of values to a comma separated string values. 
/// </summary> 
/// <typeparam name="T"></typeparam> 
/// <param name="values">The values.</param> 
/// <param name="selector">An optional selector</param> 
/// <param name="joinSeparator"></param> 
/// <returns>System.String.</returns> 
public static string ToCsv<T>(
    this IEnumerable<T> values, 
    Func<T, string> selector,    
    string joinSeparator = ",") 
{ 
    return ToCsvOpt<T>(values, selector, ReturnNullCsv.ThrowIfNull, joinSeparator); 
} 

/// <summary> 
/// Converts IEnumerable list of values to a comma separated string values. 
/// </summary> 
/// <typeparam name="T"></typeparam> 
/// <param name="values">The values.</param> 
/// <param name="returnNullCsv">Return mode (refer to enum ReturnNullCsv).</param> 
/// <param name="joinSeparator"></param> 
/// <returns>System.String.</returns> 
public static string ToCsvOpt<T>(
    this IEnumerable<T> values, 
    ReturnNullCsv returnNullCsv = ReturnNullCsv.Never, 
    string joinSeparator = ",") 
{ 
    return ToCsvOpt<T>(values, null /*selector*/, returnNullCsv, joinSeparator); 
} 

/// <summary> 
/// Converts IEnumerable list of values to a comma separated string values. 
/// </summary> 
/// <typeparam name="T"></typeparam> 
/// <param name="values">The values.</param> 
/// <param name="selector">An optional selector</param> 
/// <param name="returnNullCsv">Return mode (refer to enum ReturnNullCsv).</param> 
/// <param name="joinSeparator"></param> 
/// <returns>System.String.</returns> 
public static string ToCsvOpt<T>(
    this IEnumerable<T> values, 
    Func<T, string> selector, 
    ReturnNullCsv returnNullCsv = ReturnNullCsv.Never, 
    string joinSeparator = ",") 
{ 
    switch (returnNullCsv) 
    { 
     case ReturnNullCsv.Never: 
      if (!values.AnyOpt()) 
       return string.Empty; 
      break; 

     case ReturnNullCsv.WhenNull: 
      if (values == null) 
       return null; 
      break; 

     case ReturnNullCsv.WhenNullOrEmpty: 
      if (!values.AnyOpt()) 
       return null; 
      break; 

     case ReturnNullCsv.ThrowIfNull: 
      if (values == null) 
       throw new ArgumentOutOfRangeException("ToCsvOpt was passed a null value with ReturnNullCsv = ThrowIfNull."); 
      break; 

     default: 
      throw new ArgumentOutOfRangeException("returnNullCsv", returnNullCsv, "Out of range."); 
    } 

    if (selector == null) 
    { 
     if (typeof(T) == typeof(Int16) || 
      typeof(T) == typeof(Int32) || 
      typeof(T) == typeof(Int64)) 
     {     
      selector = (v) => Convert.ToInt64(v).ToStringInvariant(); 
     } 
     else if (typeof(T) == typeof(decimal)) 
     { 
      selector = (v) => Convert.ToDecimal(v).ToStringInvariant(); 
     } 
     else if (typeof(T) == typeof(float) || 
       typeof(T) == typeof(double)) 
     { 
      selector = (v) => Convert.ToDouble(v).ToString(CultureInfo.InvariantCulture); 
     } 
     else 
     { 
      selector = (v) => v.ToString(); 
     }    
    } 

    return String.Join(joinSeparator, values.Select(v => selector(v))); 
} 

public static string ToStringInvariantOpt(this Decimal? d) 
{ 
    return d.HasValue ? d.Value.ToStringInvariant() : null; 
} 

public static string ToStringInvariant(this Decimal d) 
{ 
    return d.ToString(CultureInfo.InvariantCulture); 
} 

public static string ToStringInvariantOpt(this Int64? l) 
{ 
    return l.HasValue ? l.Value.ToStringInvariant() : null; 
} 

public static string ToStringInvariant(this Int64 l) 
{ 
    return l.ToString(CultureInfo.InvariantCulture); 
} 

public static string ToStringInvariantOpt(this Int32? i) 
{ 
    return i.HasValue ? i.Value.ToStringInvariant() : null; 
} 

public static string ToStringInvariant(this Int32 i) 
{ 
    return i.ToString(CultureInfo.InvariantCulture); 
} 

public static string ToStringInvariantOpt(this Int16? i) 
{ 
    return i.HasValue ? i.Value.ToStringInvariant() : null; 
} 

public static string ToStringInvariant(this Int16 i) 
{ 
    return i.ToString(CultureInfo.InvariantCulture); 
} 
संबंधित मुद्दे