Create a gist now

Instantly share code, notes, and snippets.

@sbrl /CSVWriter.cs
Last active Dec 22, 2015

A simple, flexible CSV writer for C#. Modeled on the StreamWriter class.
/******************************************************************************
* CSVWriter
******************************************************************************
* Version 0.8
* Author: Starbeamrainbowlabs <feedback at starbeamrainbowlabs dot com>
*
* An easy way to generate CSV files. Please allow this comment to remain
* intact.
******************************************************************************
* Changelog
******************************************************************************
* 22nd December 2015:
* - Uploaded to GitHub gist.
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace CSVHandler
{
/// <summary>
/// A class that aids the writing of a (hopefully) fully valid CSV file.
/// </summary>
public class CSVWriter
{
/// <summary>
/// The destination stream to which we will be writing the csv.
/// </summary>
private StreamWriter destination;
/// <summary>
/// Whether the underlying filestream is open or closed. True if the stream is open, false if closed.
/// </summary>
public bool IsOpen
{
get
{
return destination.BaseStream != null;
}
}
/// <summary>
/// Whether the headers have been writteen yet or not.
/// </summary>
private bool headersWritten = false;
/// <summary>
/// Whether the headers have been written.
/// Note that attempting to write the headers again when they have already been written results in an exception been thrown.
/// </summary>
public bool HeadersWritten
{
get
{
return headersWritten;
}
}
/// <summary>
/// The number of fields that were specified when writing the headers.
/// </summary>
private int fieldCount;
/// <summary>
/// The number of fields declared when writing the headers. Records written to the CSV writer must have this number of fields, even if they are just empty strings.
/// </summary>
public int FieldCount
{
get
{
return fieldCount;
}
}
/// <summary>
/// The number of records that have been written to the output stream so far.
/// </summary>
private int recordsWritten = 0;
/// <summary>
/// The number of records written to the output stream so far. Note that this doesn't include the header line.
/// </summary>
public int RecordsWritten
{
get
{
return recordsWritten;
}
}
/// <summary>
/// Creates a new CSV writer that will write out to the given filename.
/// </summary>
/// <param name="filename">The filename to write the csv to.</param>
public CSVWriter(string filename) : this(new StreamWriter(filename))
{
}
/// <summary>
/// Creates a new CSV writer that will write to the given StreamWriter.
/// </summary>
/// <param name="inDestination">The StreamWriter to write the csv to.</param>
public CSVWriter(StreamWriter inDestination)
{
destination = inDestination;
}
/// <summary>
/// Encapsulates a given string in quotes if it contains a comma.
/// Rather useful when preparing cell data for writing.
/// </summary>
/// <param name="cellData">The string to check.</param>
/// <returns>The properly escaped string.</returns>
private string escapeCellData(string cellData)
{
if (cellData.Contains(","))
return String.Format("\"{0}\"", cellData);
else
return cellData;
}
/// <summary>
/// Writes the header contained in the given array to the file.
/// </summary>
/// <param name="inHeaders">The headers to write to the csv file.</param>
public void WriteHeader(string[] inHeaders)
{
// Blow up if we try to write the headersmeor than once.
if(headersWritten)
throw new InvalidOperationException("You cannot write the CSV headers more than once.");
// Save the number of headers for later
fieldCount = inHeaders.Length;
// Loop over each header and prepare it for writing. This encapsulates the header in quotes if it contians a comma.
string[] preparedHeaders = new string[inHeaders.Length];
for(int i = 0; i < inHeaders.Length; i++)
{
preparedHeaders[i] = escapeCellData(inHeaders[i]);
}
destination.WriteLine(String.Join(",", preparedHeaders));
headersWritten = true;
}
/// <summary>
/// Writes a new record to the csv file.
/// Note that the number of fields in the data provided must the equal to that declared when writing the header.
/// </summary>
/// <param name="data">An array of records to write out.</param>
public void WriteRecord(string[] data)
{
if(data.Length != FieldCount)
throw new FormatException(String.Format("Data does not have the expected number of fields. Expected: {0}, Actual: {1}", data.Length, FieldCount));
string[] preparedData = new string[data.Length];
for(int i = 0; i < data.Length; i++)
{
preparedData[i] = escapeCellData(data[i]);
}
destination.WriteLine(String.Join(",", preparedData));
recordsWritten++;
}
/// <summary>
/// Closes the underlying StreamWriter.
/// Don't attempt to write to the CSV writer after you've closed the file, as this will throw an exception!
/// </summary>
public void Close()
{
destination.Close();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment