将通用列表转换为CSVstring
我有一个整数值列表(列表),并希望生成一个逗号分隔值的string。 这是列表中的所有项目输出到一个逗号分隔列表。
我的想法… 1.将列表传递给一个方法。 2.使用stringbuilder迭代列表并附加逗号3.testing最后一个字符,如果是逗号,则将其删除。
你怎么看? 这是最好的方法吗?
如果我想要处理的不仅是整数(我现在的计划),而且还有string,longs,double,bools等等,那么我的代码如何改变? 我想让它接受任何types的列表。
这个框架已经为我们做了什么了不起。
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()
有关这种轻微变化的有趣阅读:请参阅Eric Lippert博客上的Comma Quibbling 。
注意:这是在.NET 4.0正式发布之前编写的。 现在我们可以说
IEnumerable<T> sequence; string csv = String.Join(",", sequence);
使用重载String.Join<T>(string, IEnumerable<T>)
。 这个方法会自动将每个元素x
x.ToString()
到x.ToString()
。
在3.5,我仍然能够做到这一点。 它更简单,不需要lambda。
String.Join(",", myList.ToArray<string>());
您可以创build一个可以在任何IEnumerable上调用的扩展方法:
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 commaSeparated = myList.JoinStrings(", ");
你可以使用String.Join
。
String.Join( ",", Array.ConvertAll( list.ToArray(), element => element.ToString() ) );
如果任何主体想要转换自定义类对象 列表而不是string列表 ,请用您的类的csv行表示来覆盖类的ToString方法。
Public Class MyClass{ public int Id{get;set;} public String PropertyA{get;set;} public override string ToString() { return this.Id+ "," + this.PropertyA; } }
然后,可以使用以下代码将此类列表转换为带有标题列的 CSV
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());
由@Frank给出的链接中的代码从.NET通用列表中创build一个CSV文件有一个结束每一行的一个小问题,
我修改了代码以摆脱它。希望它有助于某人。
/// <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); } } }
任何解决scheme只有在列表(string)
如果你有一个你自己的对象的列表(如汽车)其中车有n个属性,你必须循环每个汽车对象的属性信息。
看看: http : //www.csharptocsharp.com/generate-csv-from-generic-list
我在这篇文章中深入解释。 我只是在这里粘贴代码和简短的描述。
这是创build标题行的方法。 它使用属性名称作为列名称。
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); }
此方法创build所有的值行
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); } }
这是将它们结合在一起并创build实际文件的方法。
public static void CreateCSV<T>(List<T> list, string filePath) { using (StreamWriter sw = new StreamWriter(filePath)) { CreateHeader(list, sw); CreateRows(list, sw); } }
我喜欢一个很好的简单的扩展方法
public static string ToCsv(this List<string> itemList) { return string.Join(",", itemList); }
然后,您可以在原始列表中调用该方法:
string CsvString = myList.ToCsv();
比其他一些build议更清洁,更易于阅读。
CsvHelper图书馆在Nuget中非常受欢迎,值得! https://github.com/JoshClose/CsvHelper/wiki/Basics
使用CsvHelper非常简单。 它的默认设置是为最常见的场景设置的。
这里有一些设置数据。
Actors.csv:
Id,FirstName,LastName 1,Arnold,Schwarzenegger 2,Matt,Damon 3,Christian,Bale
Actor.cs(代表演员的自定义类对象):
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" ) );
var actorsList = csv.GetRecords();
写入一个CSV文件。
using (var csv = new CsvWriter( new StreamWriter( "Actors.csv" ) )) { csv.WriteRecords( actorsList ); }
http://cc.davelozinski.com/c-sharp/the-fastest-way-to-read-and-process-text-files
本网站做了一些关于如何使用缓冲作家写入文件的广泛testing,逐行阅读似乎是最好的方法,使用string生成器是最慢的之一。
我使用他的技术很多东西来写文件,它运作良好。
String.Join的问题在于你没有处理值中已经存在逗号的情况。 如果存在逗号,则在引号中包围该值,并用双引号replace所有现有的引号。
String.Join(",",{"this value has a , in it","This one doesn't", "This one , does"});
请参阅CSV模块
通用ToCsv()扩展方法:
- 支持Int16 / 32/64,float,double,decimal和任何支持ToString()
- 可选的定制连接分隔符
- 可选自定义select器
- 可选的空/空处理规范(* Opt()重载)
用法示例:
"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); }