2009-05-20 136 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();