Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Writing a DataTable to a CSV File

0.00/5 (No votes)
8 Sep 2017 1  
A quick way to write the contents of a DataTable to an RFC 4180-compliant CSV file

Introduction

There are many times when we need to export the contents of a DataTable to a format compatible with spreadsheet applications, such as Microsoft Excel or Apple Numbers. This quick little class will write the contents of a DataTable to a TextWriter instance, whether this is a physical file or network stream.

Here's the class itself:

// C# Code

using System.Data;
using System.IO;
using System.Linq;

public static class Rfc4180Writer 
{
    public static void WriteDataTable(DataTable sourceTable, TextWriter writer, bool includeHeaders) 
    {
        if (includeHeaders) {
            IEnumerable<String> headerValues = sourceTable.Columns
                .OfType<DataColumn>()
                .Select(column => QuoteValue(column.ColumnName));
                
            writer.WriteLine(String.Join(",", headerValues));
        }

        IEnumerable<String> items = null;

        foreach (DataRow row in sourceTable.Rows) {
            items = row.ItemArray.Select(o => QuoteValue(o?.ToString() ?? String.Empty));
            writer.WriteLine(String.Join(",", items));
        }

        writer.Flush();
    }

    private static string QuoteValue(string value) 
    {
        return String.Concat("\"", 
        value.Replace("\"", "\"\""), "\"");
    }
} 
'VB Code

Imports System.Data
Imports System.IO
Imports System.Linq

Public Class Rfc4180Writer
    Public Shared Sub WriteDataTable(ByVal sourceTable As DataTable, _
    	ByVal writer As TextWriter, ByVal includeHeaders As Boolean)
        If (includeHeaders) Then
            Dim headerValues As IEnumerable(Of String) = sourceTable.Columns
                .OfType(Of DataColumn)
                .Select(Function(column) QuoteValue(column.ColumnName))

            writer.WriteLine(String.Join(",", headerValues))
        End If

        Dim items As IEnumerbale(Of String) = Nothing
        For Each row As DataRow In sourceTable.Rows
            items = row.ItemArray.Select(Function(obj) QuoteValue(If(obj?.ToString(), String.Empty)))
            writer.WriteLine(String.Join(",", items)
        Next

        writer.Flush()
    End Sub

    Private Shared Function QuoteValue(ByVal value As String) As String
        Return String.Concat("""", value.Replace("""", """"""), """")
    End Function
End Class 

Using the Code

Making use of the class is straightforward in a number of applications. For the desktop world, here's a console app demonstrating the use via StreamWriter:

// C# Code
public static class Program {
    public static void Main() {
        DataTable sourceTable = new DataTable();

        sourceTable.Columns.AddRange(new DataColumn[] {
            new DataColumn("ID", typeof(Guid)),
            new DataColumn("Date", typeof(DateTime)),
            new DataColumn("StringValue", typeof(string)),
            new DataColumn("NumberValue", typeof(int)),
            new DataColumn("BooleanValue", typeof(bool))
        });

        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String1", 100, true);
        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String2", 200, false);
        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String3", 300, true);

        using (StreamWriter writer = new StreamWriter("C:\\Temp\\dump.csv")) {
            Rfc4180Writer.WriteDataTable(sourceTable, writer, true);
        }
    }
} 
 ' VB Code
Public Class Program
    Public Shared Sub Main()
        Dim sourceTable As DataTable = New DataTable()
        
        sourceTable.Columns.AddRange(New DataColumn() {
            New DataColumn("ID", GetType(Guid)),
            New DataColumn("Date", GetType(Date)),
            New DataColumn("StringValue", GetType(String)),
            New DataColumn("NumberValue", GetType(Integer)),
            New DataColumn("BooleanValue", GetType(Boolean))
        })
        
        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String1", 100, True)
        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String2", 200, False)
        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String3", 300, True)
        
        Using writer As StreamWriter = New StreamWriter("C:\Temp\dump.csv")
            Rfc4180Writer.WriteDataTable(sourceTable, writer, True)
        End Using
    End Sub
End Class  

For the ASP.NET MVC world, specifically MVC 3 or later, the demonstration isn't much different than the above example except the result is returned as a FilePathResult instance on a controller action:

// C# Code
public class ReportController : Controller
{
    [HttpGet()]
    public ActionResult Export()
    {
        DataTable sourceTable = new DataTable();

        sourceTable.Columns.AddRange(new DataColumn[] {
            new DataColumn("ID", typeof(Guid)),
            new DataColumn("Date", typeof(DateTime)),
            new DataColumn("StringValue", typeof(string)),
            new DataColumn("NumberValue", typeof(int)),
            new DataColumn("BooleanValue", typeof(bool))
        });

        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String1", 100, true);
        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String2", 200, false);
        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String3", 300, true);

        byte[] outputBuffer = null;

        using (MemoryStream tempStream = new MemoryStream()) {
            using (StreamWriter writer = new StreamWriter(tempStream)) {
                Rfc4180Writer.WriteDataTable(sourceTable, writer, true);
            }

            outputBuffer = tempStream.ToArray();
        }

        return File(outputBuffer, "text/csv", "export.csv");
    }
} 
' VB Code
Public Class ReportController
    Inherits Controller

    <HttpGet()> _
    Public Function Export() As ActionResult
        Dim sourceTable As DataTable = New DataTable()

        sourceTable.Columns.AddRange(New DataColumn() {
            New DataColumn("ID", GetType(Guid)),
            New DataColumn("Date", GetType(Date)),
            New DataColumn("StringValue", GetType(String)),
            New DataColumn("NumberValue", GetType(Integer)),
            New DataColumn("BooleanValue", GetType(Boolean))
        })

        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String1", 100, True)
        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String2", 200, False)
        sourceTable.Rows.Add(Guid.NewGuid(), DateTime.Now, "String3", 300, True)

        Dim outputBuffer() As Byte = Nothing
        Using tempStream As MemoryStream = New MemoryStream()
            Using writer As StreamWriter = New StreamWriter(tempStream)
                Rfc4180Writer.WriteDataTable(sourceTable, writer, True)
            End Using

            outputBuffer = tempStream.ToArray()
        End Using

        Return File(outputBuffer, "text/csv", "export.csv")
    End Function

End Class

Points of Interest

If you're not familiar with the original RFC, take a second to read it over at http://tools.ietf.org/html/rfc4180.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here