2009-05-20 134 views
28

当前有一个DataTable,但希望通过WebHandler将其流式传输给用户。 FileHelpersCommonEngine.DataTableToCsv(dt, "file.csv")。但它将其保存到文件中。我怎样才能将它保存到流?当我知道高级中的列或者他们没有更改时我知道该怎么做,但我想直接从数据表中生成列标题。将DataTable转换为CSV流

如果我知道这个栏目我刚刚创建类:

[DelimitedRecord(",")] 
public class MailMergeFields 
{ 
    [FieldQuoted()] 
    public string FirstName; 
    [FieldQuoted()] 
    public string LastName; 
} 

然后使用FileHelperEngine并添加记录:

FileHelperEngine engine = new FileHelperEngine(typeof(MailMergeFields)); 

MailMergeFields[] merge = new MailMergeFields[dt.Rows.Count + 1]; 

// add headers 
merge[0] = new MailMergeFields(); 
merge[0].FirstName = "FirstName"; 
merge[0].LastName = "LastName"; 

int i = 1;    
// add records 
foreach (DataRow dr in dt.Rows) 
{ 
    merge[i] = new MailMergeFields(); 
    merge[i].FirstName = dr["Forename"]; 
    merge[i].LastName = dr["Surname"]; 
    i++; 
} 

最后写入流:

TextWriter writer = new StringWriter(); 
engine.WriteStream(writer, merge); 
context.Response.Write(writer.ToString()); 

不幸的是,由于我之前并不了解专栏,所以我无法事先创建课程。

+0

您可以检查此https://gist.github.com/riyadparvez/4467668 – user 2013-03-12 06:53:13

+0

文件助手库是开源的。你为什么不破解它并添加你自己的方法? – Keltex 2009-05-20 14:19:23

+0

@user:这个要点包含一个错误,其中包含逗号的条目将无法正确处理。请参阅http://stackoverflow.com/q/769621/1461424 – Krumia 2016-12-29 13:02:08

回答

65

你可以随便写东西很快自己:

public static class Extensions 
{ 
    public static string ToCSV(this DataTable table) 
    { 
     var result = new StringBuilder(); 
     for (int i = 0; i < table.Columns.Count; i++) 
     { 
      result.Append(table.Columns[i].ColumnName); 
      result.Append(i == table.Columns.Count - 1 ? "\n" : ","); 
     } 

     foreach (DataRow row in table.Rows) 
     { 
      for (int i = 0; i < table.Columns.Count; i++) 
      { 
       result.Append(row[i].ToString()); 
       result.Append(i == table.Columns.Count - 1 ? "\n" : ","); 
      } 
     } 

     return result.ToString(); 
    } 
} 

,并测试:

public static void Main() 
    { 
     DataTable table = new DataTable(); 
     table.Columns.Add("Name"); 
     table.Columns.Add("Age"); 
     table.Rows.Add("John Doe", "45"); 
     table.Rows.Add("Jane Doe", "35"); 
     table.Rows.Add("Jack Doe", "27"); 
     var bytes = Encoding.GetEncoding("iso-8859-1").GetBytes(table.ToCSV()); 
     MemoryStream stream = new MemoryStream(bytes); 

     StreamReader reader = new StreamReader(stream); 
     Console.WriteLine(reader.ReadToEnd()); 
    } 

编辑:回复您的评论:

这取决于你希望你的csv格式化,但通常如果文本包含特殊字符,你想用双引号括起来,例如:“my,text”。您可以在创建csv的代码中添加检查以检查特殊字符,并在双引号中包含文本(如果是)。至于.NET 2.0的东西,只需在你的类中创建它作为一个辅助方法,或者在方法声明中删除这个词并像这样调用它:Extensions.ToCsv(table);

2

如果你可以把你的数据表到一个IEnumerable这应该为你工作...

Response.Clear(); 
    Response.Buffer = true; 

    Response.AddHeader("content-disposition", "attachment;filename=FileName.csv"); 
    Response.Charset = ""; 
    Response.ContentType = "application/text"; 
    Response.Output.Write(ExampleClass.ConvertToCSV(GetListOfObject(), typeof(object))); 
    Response.Flush(); 
    Response.End(); 



public static string ConvertToCSV(IEnumerable col, Type type) 
     { 
      StringBuilder sb = new StringBuilder(); 
      StringBuilder header = new StringBuilder(); 

      // Gets all properies of the class 
      PropertyInfo[] pi = type.GetProperties(); 

      // Create CSV header using the classes properties 
      foreach (PropertyInfo p in pi) 
      { 
       header.Append(p.Name + ","); 
      } 

      sb.AppendLine(header.ToString().Remove(header.Length)); 

      foreach (object t in col) 
      { 
       StringBuilder body = new StringBuilder(); 

       // Create new item 
       foreach (PropertyInfo p in pi) 
       { 
        object o = p.GetValue(t, null); 
        body.Append(o.ToString() + ","); 
       } 

       sb.AppendLine(body.ToString().Remove(body.Length)); 
      } 
      return sb.ToString(); 
     } 
1

你可以尝试使用这样的东西。 在这种情况下,我使用一个存储过程来获取更多数据表并使用CSV导出所有数据表 。

using System; 
using System.Text; 
using System.Data; 
using System.Data.SqlClient; 
using System.IO; 

namespace bo 
{ 
class Program 
{ 
    static private void CreateCSVFile(DataTable dt, string strFilePath) 
    { 
     #region Export Grid to CSV 
     // Create the CSV file to which grid data will be exported. 
     StreamWriter sw = new StreamWriter(strFilePath, false); 
     int iColCount = dt.Columns.Count; 

     // First we will write the headers. 

     //DataTable dt = m_dsProducts.Tables[0]; 
     for (int i = 0; i < iColCount; i++) 
     { 
      sw.Write(dt.Columns[i]); 
      if (i < iColCount - 1) 
      { 
       sw.Write(";"); 
      } 
     } 
     sw.Write(sw.NewLine); 

     // Now write all the rows. 
     foreach (DataRow dr in dt.Rows) 
     { 
      for (int i = 0; i < iColCount; i++) 
      { 
       if (!Convert.IsDBNull(dr[i])) 
       { 
        sw.Write(dr[i].ToString()); 
       } 
       if (i < iColCount -1) 
       { 
        sw.Write(";"); 
       } 
      } 
      sw.Write(sw.NewLine); 
     } 
     sw.Close(); 

     #endregion 
    } 
    static void Main(string[] args) 
    { 
     string strConn = "connection string to sql"; 
     string direktorij = @"d:"; 
     SqlConnection conn = new SqlConnection(strConn); 
     SqlCommand command = new SqlCommand("sp_ado_pos_data", conn); 
     command.CommandType = CommandType.StoredProcedure; 
     command.Parameters.Add('@skl_id', SqlDbType.Int).Value = 158; 
     SqlDataAdapter adapter = new SqlDataAdapter(command); 
     DataSet ds = new DataSet(); 
     adapter.Fill(ds); 
     for (int i = 0; i < ds.Tables.Count; i++) 
     { 
      string datoteka = (string.Format(@"{0}tablea{1}.csv", direktorij, i)); 
      DataTable tabela = ds.Tables[i]; 
      CreateCSVFile(tabela,datoteka); 
      Console.WriteLine("Generišem tabelu {0}", datoteka); 
     } 
     Console.ReadKey(); 
    } 
    } 
} 
0

BFree的答案为我工作。我需要将流正确发布到浏览器。我认为这是一种常见的选择。我增加了以下内容贝丽的main()的代码来做到这一点:

//StreamReader reader = new StreamReader(stream); 
//Console.WriteLine(reader.ReadToEnd()); 

string fileName = "fileName.csv"; 
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; 
HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", fileName)); 
stream.Position = 0; 
stream.WriteTo(HttpContext.Current.Response.OutputStream); 
1

我用下面的代码,从别人的博客掠夺(请原谅缺乏引文)。它通过引用每个字段的值,以合理优雅的方式处理报价,换行符和逗号。

/// <summary> 
    /// Converts the passed in data table to a CSV-style string.  
    /// </summary> 
    /// <param name="table">Table to convert</param> 
    /// <returns>Resulting CSV-style string</returns> 
    public static string ToCSV(this DataTable table) 
    { 
     return ToCSV(table, ",", true); 
    } 

    /// <summary> 
    /// Converts the passed in data table to a CSV-style string. 
    /// </summary> 
    /// <param name="table">Table to convert</param> 
    /// <param name="includeHeader">true - include headers<br/> 
    /// false - do not include header column</param> 
    /// <returns>Resulting CSV-style string</returns> 
    public static string ToCSV(this DataTable table, bool includeHeader) 
    { 
     return ToCSV(table, ",", includeHeader); 
    } 

    /// <summary> 
    /// Converts the passed in data table to a CSV-style string. 
    /// </summary> 
    /// <param name="table">Table to convert</param> 
    /// <param name="includeHeader">true - include headers<br/> 
    /// false - do not include header column</param> 
    /// <returns>Resulting CSV-style string</returns> 
    public static string ToCSV(this DataTable table, string delimiter, bool includeHeader) 
    { 
     var result = new StringBuilder(); 

     if (includeHeader) 
     { 
      foreach (DataColumn column in table.Columns) 
      { 
       result.Append(column.ColumnName); 
       result.Append(delimiter); 
      } 

      result.Remove(--result.Length, 0); 
      result.Append(Environment.NewLine); 
     } 

     foreach (DataRow row in table.Rows) 
     { 
      foreach (object item in row.ItemArray) 
      { 
       if (item is DBNull) 
        result.Append(delimiter); 
       else 
       { 
        string itemAsString = item.ToString(); 
        // Double up all embedded double quotes 
        itemAsString = itemAsString.Replace("\"", "\"\""); 

        // To keep things simple, always delimit with double-quotes 
        // so we don't have to determine in which cases they're necessary 
        // and which cases they're not. 
        itemAsString = "\"" + itemAsString + "\""; 

        result.Append(itemAsString + delimiter); 
       } 
      } 

      result.Remove(--result.Length, 0); 
      result.Append(Environment.NewLine); 
     } 

     return result.ToString(); 
    } 
12

更新1

我已经修改了它使用的StreamWriter代替,添加一个选项来检查,如果你在你的输出需要列标题。

public static bool DataTableToCSV(DataTable dtSource, StreamWriter writer, bool includeHeader) 
{ 
    if (dtSource == null || writer == null) return false; 

    if (includeHeader) 
    { 
     string[] columnNames = dtSource.Columns.Cast<DataColumn>().Select(column => "\"" + column.ColumnName.Replace("\"", "\"\"") + "\"").ToArray<string>(); 
     writer.WriteLine(String.Join(",", columnNames)); 
     writer.Flush(); 
    } 

    foreach (DataRow row in dtSource.Rows) 
    { 
     string[] fields = row.ItemArray.Select(field => "\"" + field.ToString().Replace("\"", "\"\"") + "\"").ToArray<string>(); 
     writer.WriteLine(String.Join(",", fields)); 
     writer.Flush(); 
    } 

    return true; 
} 

正如你所看到的,你可以选择初始StreamWriter的输出,如果你使用 的StreamWriter(流BaseStream),你可以写CSV到MemeryStream文件流等

产地

我有一个简单的数据表到CSV功能,它提供我很好:

public static void DataTableToCsv(DataTable dt, string csvFile) 
    { 
     StringBuilder sb = new StringBuilder(); 

     var columnNames = dt.Columns.Cast<DataColumn>().Select(column => "\"" + column.ColumnName.Replace("\"", "\"\"") + "\"").ToArray(); 
     sb.AppendLine(string.Join(",", columnNames)); 

     foreach (DataRow row in dt.Rows) 
     { 
      var fields = row.ItemArray.Select(field => "\"" + field.ToString().Replace("\"", "\"\"") + "\"").ToArray(); 
      sb.AppendLine(string.Join(",", fields)); 
     } 

     File.WriteAllText(csvFile, sb.ToString(), Encoding.Default); 
    } 
1
public void CreateCSVFile(DataTable dt, string strFilePath,string separator) 
     {    
      #region Export Grid to CSV 
      // Create the CSV file to which grid data will be exported. 

      StreamWriter sw = new StreamWriter(strFilePath, false); 
      int iColCount = dt.Columns.Count; 
      for (int i = 0; i < iColCount; i++) 
      {  
       sw.Write(dt.Columns[i]);  
       if (i < iColCount - 1) 
       { 
        sw.Write(separator); 
       } 
      }  

      sw.Write(sw.NewLine); 

      // Now write all the rows. 
      foreach (DataRow dr in dt.Rows) 
      { 
       for (int i = 0; i < iColCount; i++) 
       { 
        if (!Convert.IsDBNull(dr[i])) 
        { 
         sw.Write(dr[i].ToString()); 
        } 

        if (i < iColCount - 1) 
        { 
         sw.Write(separator); 
        } 
       } 
       sw.Write(sw.NewLine); 
      } 

      sw.Close(); 
      #endregion 
     } 
2

我不知道这是否从VB转换为C#好,但如果你不想在你的号码报价,你可以按照以下方式进行比较的数据类型..

public string DataTableToCSV(DataTable dt) 
{ 
    StringBuilder sb = new StringBuilder(); 
    if (dt == null) 
     return ""; 

    try { 
     // Create the header row 
     for (int i = 0; i <= dt.Columns.Count - 1; i++) { 
      // Append column name in quotes 
      sb.Append("\"" + dt.Columns[i].ColumnName + "\""); 
      // Add carriage return and linefeed if last column, else add comma 
      sb.Append(i == dt.Columns.Count - 1 ? "\n" : ","); 
     } 


     foreach (DataRow row in dt.Rows) { 
      for (int i = 0; i <= dt.Columns.Count - 1; i++) { 
       // Append value in quotes 
       //sb.Append("""" & row.Item(i) & """") 

       // OR only quote items that that are equivilant to strings 
       sb.Append(object.ReferenceEquals(dt.Columns[i].DataType, typeof(string)) || object.ReferenceEquals(dt.Columns[i].DataType, typeof(char)) ? "\"" + row[i] + "\"" : row[i]); 

       // Append CR+LF if last field, else add Comma 
       sb.Append(i == dt.Columns.Count - 1 ? "\n" : ","); 
      } 
     } 
     return sb.ToString; 
    } catch (Exception ex) { 
     // Handle the exception however you want 
     return ""; 
    } 

} 
2

如果你想流CSV输出给用户而不创建文件,然后我发现以下是最简单的方法。您可以使用任何扩展/方法来创建ToCsv()函数(它会根据给定的DataTable返回一个字符串)。

 var report = myDataTable.ToCsv(); 
     var bytes = Encoding.GetEncoding("iso-8859-1").GetBytes(report); 

     Response.Buffer = true; 
     Response.Clear(); 
     Response.AddHeader("content-disposition", "attachment; filename=report.csv"); 
     Response.ContentType = "text/csv"; 
     Response.BinaryWrite(bytes); 
     Response.End();