2009-05-20 34 views
28

Hiện có DataTable, nhưng muốn truyền dữ liệu đó tới người dùng thông qua WebHandler. FileHelpersCommonEngine.DataTableToCsv(dt, "file.csv"). Tuy nhiên nó lưu nó vào một tập tin. Tôi có thể lưu nó vào luồng thay thế bằng cách nào? Tôi biết làm thế nào để làm điều đó khi tôi biết các cột trong nâng cao hoặc họ không thay đổi, nhưng tôi muốn tạo ra các tiêu đề cột ngay từ bảng dữ liệu.Chuyển đổi DataTable sang luồng CSV

Nếu tôi biết các cột tôi chỉ cần tạo các lớp:

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

Sau đó sử dụng FileHelperEngine và thêm các hồ sơ:

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

Cuối cùng viết thư cho một dòng:

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

Thật không may là tôi không biết các cột trước khi bàn tay, tôi không thể tạo lớp trước khi bàn tay.

+0

Bạn có thể kiểm tra https://gist.github.com/riyadparvez/4467668 – user

+0

Thư viện Trình trợ giúp tệp này là nguồn mở. Tại sao bạn không crack vào nó và thêm phương pháp của riêng bạn? – Keltex

+0

@user: Gist này chứa lỗi trong đó các mục nhập bằng dấu phẩy sẽ không được xử lý chính xác. Xem http://stackoverflow.com/q/769621/1461424 – Krumia

Trả lời

65

Bạn chỉ có thể viết một cái gì đó nhanh chóng tự hỏi:

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

Và để kiểm tra:

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

EDIT: Hãy bình luận của bạn:

Nó phụ thuộc vào cách bạn muốn định dạng csv của bạn nhưng nói chung nếu văn bản chứa các ký tự đặc biệt, bạn muốn kèm theo nó trong dấu ngoặc kép, ví dụ: "my, text". Bạn có thể thêm kiểm tra trong mã mà tạo ra các csv để kiểm tra các ký tự đặc biệt và kèm theo văn bản trong dấu ngoặc kép nếu nó được. Đối với điều .NET 2.0, chỉ cần tạo nó như là một phương thức trợ giúp trong lớp của bạn hoặc loại bỏ từ này trong khai báo phương thức và gọi nó như sau: Extensions.ToCsv (bảng);

+18

Điều gì sẽ xảy ra khi dữ liệu bao gồm báo giá, dòng mới hoặc dấu phẩy? – SamWM

+0

Cũng sử dụng .NET 2.0 – SamWM

+0

Điều này phù hợp với tôi. Tinh chỉnh một chút cho nhu cầu của tôi. Excel hiển thị dòng mới là? mặc dù (có cùng một vấn đề khi xuất từ ​​SQL Server) – SamWM

2

Nếu bạn có thể biến DataTable của bạn thành một IEnumerable này nên làm việc cho bạn ...

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

Cảm ơn, fyi - header.Length & body.Length nên là -1 – downatone

1

Bạn có thể thử sử dụng một cái gì đó như thế này. Trong trường hợp này, tôi đã sử dụng một thủ tục được lưu trữ để có được nhiều bảng dữ liệu hơn và xuất tất cả các bảng đó bằng cách sử dụng 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

Câu trả lời của BFree làm việc cho tôi. Tôi cần đăng luồng trực tiếp lên trình duyệt. Mà tôi tưởng tượng là một lựa chọn phổ biến. Tôi đã thêm mã sau đây vào mã Chính của BFree để thực hiện việc này:

//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

Tôi đã sử dụng mã sau đây, bị cướp từ blog của ai đó (xin tha thứ vì thiếu trích dẫn). Nó sẽ chăm sóc các trích dẫn, dòng mới và dấu phẩy một cách hợp lý thanh lịch bằng cách trích dẫn từng giá trị trường.

/// <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

Cập nhật 1

tôi đã sửa đổi nó để sử dụng StreamWriter thay vào đó, thêm một tùy chọn để kiểm tra xem bạn cần tiêu đề cột trong đầu ra của bạn.

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

Như bạn thấy, bạn có thể chọn ra bởi StreamWriter ban đầu, nếu bạn sử dụng StreamWriter (Stream BaseStream), bạn có thể viết csv vào MemeryStream, FileStream vv

xứ

tôi có một DataTable dễ chức năng csv, nó phục vụ tốt cho tôi:

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

Tôi không biết nếu điều này chuyển đổi từ VB đến C# ok nhưng nếu bạn không muốn dấu ngoặc kép quanh con số của bạn, bạn có thể so sánh các kiểu dữ liệu như sau ..

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

Nếu bạn muốn các dòng CSV ra cho người dùng mà không cần tạo tệp, sau đó tôi đã tìm thấy sau đây là phương pháp đơn giản nhất. Bạn có thể sử dụng bất kỳ phần mở rộng/phương thức nào để tạo hàm ToCsv() (trả về một chuỗi dựa trên DataTable đã cho).

 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(); 
Các vấn đề liên quan