将DataTable转换为CSVstream
目前有一个DataTable,但希望通过WebHandler将其stream式传输给用户。 FileHelpers有CommonEngine.DataTableToCsv(dt, "file.csv")
。 但它将其保存到文件中。 我怎样才能把它保存到stream? 我知道如何做到这一点,当我知道在先进的列或他们没有改变,但我想直接从数据表生成列标题。
如果我知道列我刚创build类:
[DelimitedRecord(",")] public class MailMergeFields { [FieldQuoted()] public string FirstName; [FieldQuoted()] public string LastName; }
然后使用FileHelperEngine并添加logging:
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++; }
最后写一个stream:
TextWriter writer = new StringWriter(); engine.WriteStream(writer, merge); context.Response.Write(writer.ToString());
不幸的是,由于我以前不知道专栏,所以我无法事先创build课堂。
你可以自己写一些东西:
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(); } }
并testing:
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格式,但通常如果文本包含特殊字符,你想用双引号括起来,例如:“我的文本”。 您可以在创buildcsv的代码中添加检查以检查特殊字符,如果是,则将文本用双引号括起来。 至于.NET 2.0的东西,只要在你的类中创build它作为一个辅助方法,或者在方法声明中删除这个词,并像这样调用它:Extensions.ToCsv(table);
更新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来select输出,如果你使用StreamWriter(Stream BaseStream),你可以将csv写入MemeryStream,FileStream等等。
起源
我有一个简单的csv函数datatable,它为我服务:
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); }
如果你可以把你的数据表变成一个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(); }
我不知道这是否从VB转换到C#好,但如果你不想引号围绕你的数字,你可能会比较数据types如下..
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 ""; } }
如果你想CSVstream出到用户没有创build一个文件,然后我发现以下是最简单的方法。 您可以使用任何扩展/方法来创buildToCsv()函数(它会根据给定的DataTable返回一个string)。
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();
我用下面的代码,从别人的博客中掠夺(请原谅缺乏引用)。 它通过引用每个字段值来以合理优雅的方式处理报价,换行符和逗号。
/// <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(); }
你可以尝试使用这样的东西。 在这种情况下,我使用一个存储过程来获取更多的数据表,并使用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(); } } }
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 }
BFree的答案为我工作。 我需要将stream正确发布到浏览器。 我想象的是一个常见的select。 我在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);