Void’s Vault

Knowledge source for efficiency.

C#: CSV Exporting Made Easy

I found on StackOverflow a shared class allowing to easily export any data to a file, in a string or in a byte array. Thanks Chris!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
using System;
using System.Data.SqlTypes;
using System.IO;
using System.Text;
using System.Collections.Generic;
/// <summary>
/// Simple CSV export
/// Example:
///   CsvExport myExport = new CsvExport();
///
///   myExport.AddRow();
///   myExport[&quot;Region&quot;] = &quot;New York, USA&quot;;
///   myExport[&quot;Sales&quot;] = 100000;
///   myExport[&quot;Date Opened&quot;] = new DateTime(2003, 12, 31);
///
///   myExport.AddRow();
///   myExport[&quot;Region&quot;] = &quot;Sydney \&quot;in\&quot; Australia&quot;;
///   myExport[&quot;Sales&quot;] = 50000;
///   myExport[&quot;Date Opened&quot;] = new DateTime(2005, 1, 1, 9, 30, 0);
///
/// Then you can do any of the following three output options:
///   string myCsv = myExport.Export();
///   myExport.ExportToFile(&quot;Somefile.csv&quot;);
///   byte[] myCsvData = myExport.ExportToBytes();
/// </summary>
public class CsvExport
{
  /// <summary>
  /// To keep the ordered list of column names
  /// </summary>
  List<string> fields = new List<string>();
  /// <summary>
  /// The list of rows
  /// </summary>
  List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
  /// <summary>
  /// The current row
  /// </summary>
  Dictionary<string, object> currentRow { get { return rows[rows.Count - 1]; } }
  /// <summary>
  /// Set a value on this column
  /// </summary>
  public object this[string field]
  {
    set
    {
      // Keep track of the field names, because the dictionary loses the ordering
      if (!fields.Contains(field)) fields.Add(field);
      currentRow[field] = value;
    }
  }
  /// <summary>
  /// Call this before setting any fields on a row
  /// </summary>
  public void AddRow()
  {
    rows.Add(new Dictionary<string, object>());
  }
  /// <summary>
  /// Converts a value to how it should output in a csv file
  /// If it has a comma, it needs surrounding with double quotes
  /// Eg Sydney, Australia -> &quot;Sydney, Australia&quot;
  /// Also if it contains any double quotes (&quot;), then they need to be replaced with quad quotes[sic] (&quot;&quot;)
  /// Eg &quot;Dangerous Dan&quot; McGrew -> &quot;&quot;&quot;Dangerous Dan&quot;&quot; McGrew&quot;
  /// </summary>
  string MakeValueCsvFriendly(object value)
  {
    if (value == null) return &quot;&quot;;
    if (value is INullable &amp;&amp; ((INullable)value).IsNull) return &quot;&quot;;
    if (value is DateTime)
    {
      if (((DateTime)value).TimeOfDay.TotalSeconds==0)
        return ((DateTime)value).ToString(&quot;yyyy-MM-dd&quot;);
      return ((DateTime)value).ToString(&quot;yyyy-MM-dd HH:mm:ss&quot;);
    }
    string output = value.ToString();
    if (output.Contains(&quot;,&quot;) || output.Contains(&quot;\&quot;&quot;))
      output = '&quot;' + output.Replace(&quot;\&quot;&quot;, &quot;\&quot;\&quot;&quot;) + '&quot;';
    return output;
  }
  /// <summary>
  /// Output all rows as a CSV returning a string
  /// </summary>
  public string Export()
  {
    StringBuilder sb = new StringBuilder();
    // The header
    foreach (string field in fields)
      sb.Append(field).Append(&quot;,&quot;);
    sb.AppendLine();
    // The rows
    foreach (Dictionary<string, object> row in rows)
    {
      foreach (string field in fields)
        sb.Append(MakeValueCsvFriendly(row[field])).Append(&quot;,&quot;);
      sb.AppendLine();
    }
    return sb.ToString();
  }
  /// <summary>
  /// Exports to a file
  /// </summary>
  public void ExportToFile(string path)
  {
    File.WriteAllText(path, Export());
  }
  /// <summary>
  /// Exports as raw UTF8 bytes
  /// </summary>
  public byte[] ExportToBytes()
  {
    return Encoding.UTF8.GetBytes(Export());
  }
}