Search code examples
c#csvdatatable

How can I turn a DataTable to a CSV?


Could somebody please tell me why the following code is not working. The data is saved into the csv file, however the data is not separated. It all exists within the first cell of each row.

StringBuilder sb = new StringBuilder();

foreach (DataColumn col in dt.Columns)
{
    sb.Append(col.ColumnName + ',');
}

sb.Remove(sb.Length - 1, 1);
sb.Append(Environment.NewLine);

foreach (DataRow row in dt.Rows)
{
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        sb.Append(row[i].ToString() + ",");
    }

    sb.Append(Environment.NewLine);
}

File.WriteAllText("test.csv", sb.ToString());

Solution

  • The following shorter version opens fine in Excel, maybe your issue was the trailing comma

    .net = 3.5

    StringBuilder sb = new StringBuilder(); 
    
    string[] columnNames = dt.Columns.Cast<DataColumn>().
                                      Select(column => column.ColumnName).
                                      ToArray();
    sb.AppendLine(string.Join(",", columnNames));
    
    foreach (DataRow row in dt.Rows)
    {
        string[] fields = row.ItemArray.Select(field => field.ToString()).
                                        ToArray();
        sb.AppendLine(string.Join(",", fields));
    }
    
    File.WriteAllText("test.csv", sb.ToString());
    

    .net >= 4.0

    And as Tim pointed out, if you are on .net>=4, you can make it even shorter:

    StringBuilder sb = new StringBuilder(); 
    
    IEnumerable<string> columnNames = dt.Columns.Cast<DataColumn>().
                                      Select(column => column.ColumnName);
    sb.AppendLine(string.Join(",", columnNames));
    
    foreach (DataRow row in dt.Rows)
    {
        IEnumerable<string> fields = row.ItemArray.Select(field => field.ToString());
        sb.AppendLine(string.Join(",", fields));
    }
    
    File.WriteAllText("test.csv", sb.ToString());
    

    As suggested by Christian, if you want to handle special characters escaping in fields, replace the loop block by:

    foreach (DataRow row in dt.Rows)
    {
        IEnumerable<string> fields = row.ItemArray.Select(field => 
          string.Concat("\"", field.ToString().Replace("\"", "\"\""), "\""));
        sb.AppendLine(string.Join(",", fields));
    }
    

    And last suggestion, you could write the csv content line by line instead of as a whole document, to avoid having a big document in memory.