IE浏览器< T>到CSV文件

xqk2d5yq  于 5个月前  发布在  其他
关注(0)|答案(7)|浏览(82)

我从LINQ查询中获得的结果是IEnumerable<T>类型的var
我想从LINQ的结果创建CSV文件
我正在从以下查询中获取结果

var r = from table in myDataTable.AsEnumerable()
        orderby table.Field<string>(para1)
        group table by new { Name = table[para1], Y = table[para2] }
        into ResultTable
        select new
        {
            Name = ResultTable.Key,
            Count = ResultTable.Count()
        };

字符串

uxhixvfz

uxhixvfz1#

选中此

public static class LinqToCSV
    {
        public static string ToCsv<T>(this IEnumerable<T> items)
            where T : class
        {
            var csvBuilder = new StringBuilder();
            var properties = typeof(T).GetProperties();
            foreach (T item in items)
            {
                string line = string.Join(",",properties.Select(p => p.GetValue(item, null).ToCsvValue()).ToArray());
                csvBuilder.AppendLine(line);
            }
            return csvBuilder.ToString();
        }
 
        private static string ToCsvValue<T>(this T item)
        {
            if(item == null) return "\"\"";
 
            if (item is string)
            {
                return string.Format("\"{0}\"", item.ToString().Replace("\"", "\\\""));
            }
            double dummy;
            if (double.TryParse(item.ToString(), out dummy))
            {
                return string.Format("{0}", item);
            }
            return string.Format("\"{0}\"", item);
        }
    }

字符串
完整代码:Scott Hanselman's ComputerZen Blog - From Linq To CSV

pinkon5k

pinkon5k2#

IEnumerable<string> lines = r.Select(x => String.Format("{0},{1}", r.Name, r.Count));
System.IO.File.WriteAllLines(path, lines);

字符串
将产生:

name1,count1
name2,count2
...

ilmyapht

ilmyapht3#

这是对Linq2CSV的尖叫:
http://www.codeproject.com/KB/linq/LINQtoCSV.aspx
也可以在nuget上找到:
http://nuget.org/List/Packages/LinqToCsv
很棒的图书馆,真的很推荐。

dsf9zpds

dsf9zpds4#

不清楚您真正想要什么,但这可以是一个解决方案public void Read(){

var r = from table in myDataTable.AsEnumerable()
            orderby table.Field<string>(para1)
            group table by new { Name = table[para1], Y = table[para2] }
                into ResultTable
                select new NameCount()
                {
                    Name = ResultTable.Key,
                    Count = ResultTable.Count()
                }.ToString();

    //Write all r to a File
}
public class NameCount
{
    public string Name { get; set; }
    public int Count { get; set; }
    public string ToString()
    {
        return string.Format("{0},{1}\r\n", Name, Count);
    }
}

字符串

p5cysglq

p5cysglq5#

从你的问题中我可以假设你想要一个 Generic 方法来完成这个任务,而不管T是什么?

public void ToCSV<T>(IEnumerable<T>, TextWriter writer) . . .

字符串
您无法克服的问题是,T是一个复杂类型,要用逗号分隔T的每个元素,您需要了解T的内部结构,或者T需要知道如何将其自身写为CSV行。这意味着您将需要一个ICSVRow接口,并且需要将T约束到实现ICSVRow的对象。匿名类型。
有什么问题就喊。

idfiyjo8

idfiyjo86#

这是一个基本的解决方案,我正在使用的任何IE浏览器:

using System.Reflection;
using System.Text;
//***        
    public void ToCSV<T>(IEnumerable<T> items, string filePath)
    {
        var dataTable = new DataTable(typeof(T).Name);
        PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach (var prop in props)
            dataTable.Columns.Add(prop.Name, prop.PropertyType);

        foreach (var item in items)
        {
            var values = new object[props.Length];
            for (var i = 0; i < props.Length; i++)
            {
                values[i] = props[i].GetValue(item, null);
            }
            dataTable.Rows.Add(values);
        }

        StringBuilder fileContent = new StringBuilder();
        foreach (var col in dataTable.Columns)
            fileContent.Append(col.ToString() + ",");

        fileContent.Replace(",", System.Environment.NewLine, fileContent.Length - 1, 1);

        foreach (DataRow dr in dataTable.Rows)
        {
            foreach (var column in dr.ItemArray)
                fileContent.Append("\"" + column.ToString() + "\",");

            fileContent.Replace(",", System.Environment.NewLine, fileContent.Length - 1, 1);
        }

        //good place to validate File.Exist or catch exceptions
        System.IO.File.WriteAllText(filePath, fileContent.ToString());            
    }

字符串

xbp102n0

xbp102n07#

其他解决方案没有正确地转义值。@Pranay Rana的特别包括不正确的转义,这可以说是更糟糕的。
这可能有点矫枉过正,但下面的方法将在需要时引用值,可选地允许您选择除了“,"之外的字符串,可选地允许包含头,允许您指定CSV中包含/排除的属性,甚至允许您将这些属性Map到头中的不同文本(如果需要)。
此外,它还尝试检查传入的可枚举对象的类型--因此原始类型的可枚举对象将生成单行CSV,而复杂类型的原始类型将Map其属性。它查看实际对象而不是类型参数来执行此操作,例如,保存复杂类型的object[]数组仍将Map属性。

/// <summary>
/// Converts the given enumerable into a CSV string. Optionally, specify the delimiter or include headers.
/// For enumerables of primitive types, it will convert them to a single-line CSV. Headers are not valid for this case.
/// For enumerables of complex types, it will inspect the properties and convert each item into a line of the CSV.
/// Which properties are included/excluded and the header names in the resulting CSV can be controlled.
/// Note: Headers and values will only be double-quoted if necessary as per RFC4180.
/// </summary>
/// <typeparam name="T">The type of the enumerable.</typeparam>
/// <param name="enumerable">The enumerable to turn into a CSV.</param>
/// <param name="delimiter">The delimiter.</param>
/// <param name="includeHeaders">Whether to include headers.</param>
/// <param name="propertiesToInclude">Properties from the objects given to include. If left null, all properties will be included. This does not apply for enumerables of primitive types.</param>
/// <param name="propertiesToExclude">Properties to exclude from the DataTable, if any. This does not apply for enumerables of primitive types.</param>
/// <param name="propertyNameHeaderMap">A map that will be used to translate the property names to the headers that should appear in the CSV. This does not apply for enumerables of primitive types.</param>
/// <returns>A CSV representation of the objects in the enumeration.</returns>
public static string ToCsvString<T>(
    this IEnumerable<T> enumerable, 
    char delimiter = ',', 
    bool includeHeaders = false, 
    IEnumerable<string> propertiesToInclude = null, 
    IEnumerable<string> propertiesToExclude = null, 
    Dictionary<string, string> propertyNameHeaderMap = null)
{
    if (enumerable == null) throw new ArgumentNullException(nameof(enumerable));

    var type = enumerable.FirstOrDefault()?.GetType();
    if (type == null) return "";
    
    if (type.IsSimpleType())
        return string.Join(delimiter, enumerable.Select(i => escapeCsvValue(i?.ToString(), delimiter)));

    var csvBuilder = new StringBuilder();
    var allProperties = type.GetProperties();
    var propsToIncludeSet = (propertiesToInclude ?? allProperties.Select(p => p.Name))
        .Except(propertiesToExclude ?? Enumerable.Empty<string>())
        .ToHashSet();
    var properties = allProperties
        .Where(p => propsToIncludeSet.Contains(p.Name))
        .ToList();

    if (includeHeaders)
    {
        var headerNames = properties
            .Select(p => escapeCsvValue(propertyNameHeaderMap == null ? p.Name : propertyNameHeaderMap.GetValueOrDefault(p.Name) ?? $"{nameof(propertyNameHeaderMap)} was missing a value for property {p.Name}", delimiter));

        csvBuilder.AppendLine(string.Join(delimiter, headerNames));
    }

    foreach (var item in enumerable)
    {
        var vals = properties.Select(p => escapeCsvValue(p.GetValue(item, null)?.ToString(), delimiter));
        var line = string.Join(delimiter, vals);
        csvBuilder.AppendLine(line);
    }
    return csvBuilder.ToString();

    //Function to escape a value for use in CSV. Per RFC4180, if the delimiter, newline, or double quote is present in the value it must be double quoted. If the value contains double quotes they must be escaped.
    static string escapeCsvValue(string s, char delimiter)
    {
        return s == null ? null 
            : s.Any(c => c == delimiter || c == '"' || c == '\r' || c == '\n') ? $"\"{s.Replace("\"", "\"\"")}\"" 
            : s;
    }
}

/// <summary>
/// Whether the given type is a "simple" type. Eg, a built in CLR type to represent data.
/// This includes all integral types, floating points types, DateTime, DateOnly, decimal, and Guid.
/// </summary>
/// <param name="type">The type to check.</param>
/// <param name="unwrapNullable">Whether the type inside a nullable type should be checked.</param>
/// <returns>Whether the type was a simple type.</returns>
/// <exception cref="ArgumentNullException">If type was empty.</exception>
public static bool IsSimpleType(this Type type, bool unwrapNullable = true)
{
    if (type == null) throw new ArgumentNullException(nameof(type));

    if (unwrapNullable) type = Nullable.GetUnderlyingType(type) ?? type;
    return type.IsPrimitive
           || type == typeof(string)
           || type == typeof(DateTime)
           || type == typeof(DateOnly)
           || type == typeof(decimal)
           || type == typeof(Guid)
        ;
}

字符串

相关问题