Skip to content

Instantly share code, notes, and snippets.

@josephrodriguez
Created February 26, 2015 01:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josephrodriguez/11b676f166211f5927df to your computer and use it in GitHub Desktop.
Save josephrodriguez/11b676f166211f5927df to your computer and use it in GitHub Desktop.
Generic CSV writer.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Example
{
public class CsvWriter<T> : IDisposable
{
private readonly StreamWriter _writer;
private readonly List<string> _headers;
private readonly IDictionary<Type, List<Func<object, string>>> _formatters;
private CsvWriter()
{
_headers = typeof(T).GetProperties()
.Select(p => p.Name)
.ToList();
_formatters = new Dictionary<Type, List<Func<object, string>>>();
}
public CsvWriter(string path)
:this()
{
_writer = new StreamWriter(path);
}
public CsvWriter(Stream stream)
:this()
{
_writer = new StreamWriter(stream);
}
public void WriteRow(T element)
{
var row = GetRow(element);
_writer.WriteLine(row);
}
public void WriteRows(IEnumerable<T> elements)
{
foreach (var element in elements)
WriteRow(element);
}
public void AddFormatter<V>(Func<V, string> formatter)
{
if(!_formatters.ContainsKey(typeof(V)))
_formatters.Add(typeof(V), new List<Func<object, string>>());
_formatters[typeof(V)].Add(o => formatter((V) o));
}
public void WriteHeaders()
{
var headersLine = string.Join(",", _headers.Select(FormatCamelCase));
_writer.WriteLine(headersLine);
}
public void Close()
{
_writer.Close();
}
public void Flush()
{
_writer.Flush();
}
public void Dispose()
{
_writer.Dispose();
}
private string GetRow(T element)
{
var values = _headers.Select(typeof (T).GetProperty)
.Select(property => property == null
? string.Empty
: Encode(property.PropertyType, property.GetValue(element)))
.ToList();
return string.Join(",", values);
}
private string Encode(Type type, object value)
{
if (value == null)
return string.Empty;
if (_formatters.ContainsKey(type))
{
var formatter = _formatters[type].FirstOrDefault();
if (formatter != null)
return formatter.Invoke(value);
}
var result = value.ToString();
if (result.Contains(",") || result.Contains("\""))
result = '"' + result.Replace("\"", "\"\"") + '"';
return result;
}
public string FormatCamelCase(string s)
{
var b = new StringBuilder();
var j = 0;
for (var i = 0; i < s.Length; i++)
{
b.Append(s[i]);
if (char.IsUpper(s[i]))
b.Insert(i + j++, ' ');
}
return b.ToString().TrimStart();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment