2011-06-01 7 views
9

estoy consiguiendo el resultado de la consulta LINQ como var de tipo IEnumerable<T>IEnumerable <T> a un archivo CSV

Quiero un archivo CSV que se crea a partir del resultado de la LINQ

estoy consiguiendo el resultado de la siguiente consulta

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() 
     }; 
+0

qué tipo es T? –

+0

Esta pregunta no está clara, ya hay 2 votos para cerrarla como "no es una pregunta real". Por favor, consulte http://tinyurl.com/so-hints y vea si puede mejorar la pregunta. –

Respuesta

13

Marque esta

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

código completo en: Scott Hanselman's ComputerZen Blog - From Linq To CSV

+0

Gracias por la solución – usr021986

+0

@ScottHanselman Ese código tiene un error. Intenta escapar de las comillas en cadenas usando '/' '. Eso no es correcto. Para los CSV, las comillas se escapan usando comillas dobles. Https://en.wikipedia.org/wiki/Comma-separated_values ​​ – MgSam

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

producirá:

name1,count1 
name2,count2 
... 
+0

No entiendo tu punto. Quiero crear el archivo csv a partir del resultado de IEnumrable usr021986

+0

@abatishchev: Esto no funcionará: 'IEnumerable ' no se puede convertir a 'IEnumerable '. –

+0

@Daniel: Claro, era un error tipográfico, me refiero a 'IEnumerable ', pero si OP quiere 'IEnumerable ' entonces su pregunta no tiene sentido. – abatishchev

0

Supongo que por su pregunta quiere un método genérico que hará esto, independientemente de qué T?

Algo así como

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

El problema no se puede superar, es que T es un tipo complejo, que comas separar cada elemento de T lo que necesita saber sobre el funcionamiento interno de T, o T necesidades a Saber cómo escribirlo como una fila CSV, lo que significa que necesitará una interfaz ICSVRow y que tendrá que restringir T a los objetos que implementan ICSVRow. Lo que también significa que esto no funcionará para tipos anónimos.

Cualquier pregunta simplemente grite.

+0

Sí, quiero el método genérico independientemente de la T – usr021986

+0

@ user373083: Entonces tendrá que usar la reflexión para obtener las propiedades del tipo enumerado, esta lata es una lata de gusanos, tendrá que ser muy estricto sobre lo que 'ToCSV' hará con T, o se convertirá en una pesadilla. ¿Eres bueno con la reflexión, o debería publicar algún código de cómo empezar? –

2

no está claro lo que realmente quiere, pero esto puede ser una solución vacío Leer pública() {

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

Esta es una solución básica que estoy usando para cualquier IEnumerable:

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());    
    } 
+0

Si usted es no va a manejar la excepción, no tiene sentido atraparla en primer lugar. Las excepciones deben detectarse donde se puedan manejar. – mason

+0

Es cierto que elimino parte del código que estaba usando y me olvidé de quitar también esta parte. –

Cuestiones relacionadas