Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert DataTable to CSV stream

Tags:

c#

csv

datatable

Currently have a DataTable, but wish to stream it to the user via a WebHandler. FileHelpers has CommonEngine.DataTableToCsv(dt, "file.csv"). However it saves it to a file. How can I save it to a stream instead? I know how to do it when I know the columns in advanced or they don't change, but I want to generate the column headings straight from the data table.

If I know the columns I just create the class:

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

Then use FileHelperEngine and add the records:

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

Finally write to a stream:

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

Unfortunately as I don't know the columns before hand, I can't create the class before hand.

like image 450
SamWM Avatar asked May 20 '09 14:05

SamWM


People also ask

How do I create a CSV file in C sharp?

ToString(); string csv = string. Format("{0},{1}\n", first, second); File. WriteAllText(filePath, csv); The whole function runs inside a loop, and every row should be written to the csv file.

How do I save a CSV file in C#?

String file = @"C:\Users\Sharl\Desktop\Output. csv"; Use the StringBuilder to create a new formatted string. Use the separator variable to store the comma that will separate each value for each column.


2 Answers

You can just write something quickly yourself:

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

And to test:

  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: Re your comments:

It depends on how you want your csv formatted but generally if the text contains special characters, you want to enclose it in double quotes ie: "my,text". You can add checking in the code that creates the csv to check for special characters and encloses the text in double quotes if it is. As for the .NET 2.0 thing, just create it as a helper method in your class or remove the word this in the method declaration and call it like so : Extensions.ToCsv(table);

like image 68
BFree Avatar answered Sep 22 '22 12:09

BFree


Update 1

I have modified it to use StreamWriter instead, add an option to check if you need column headers in your output.

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

As you can see, you can choose the output by initial StreamWriter, if you use StreamWriter(Stream BaseStream), you can write csv into MemeryStream, FileStream, etc.

Origin

I have an easy datatable to csv function, it serves me well:

    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);     } 
like image 40
SuperLucky Avatar answered Sep 19 '22 12:09

SuperLucky