Skip to content

Instantly share code, notes, and snippets.

@jchadwick
Created October 9, 2013 18:37
Show Gist options
  • Save jchadwick/6905978 to your computer and use it in GitHub Desktop.
Save jchadwick/6905978 to your computer and use it in GitHub Desktop.
CSV Reader/Writer
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public abstract class CsvHelper
{
protected internal const string DefaultDelimiter = ",";
protected internal static readonly char[] SpecialChars = new[] { ',', '\n', '\r', '"' };
protected internal static string Escape(string field)
{
if (field == null)
{
return "";
}
if (field.IndexOfAny(SpecialChars) != -1)
{
return String.Format("\"{0}\"", field.Replace("\"", "\"\""));
}
return field;
}
protected internal static IEnumerable<string> GetHeaders<T>()
{
return GetHeaders(typeof(T));
}
protected internal static IEnumerable<string> GetHeaders(object value)
{
if (value == null)
yield break;
if (value is IDictionary)
{
foreach (var key in (value as IDictionary).Keys)
{
if (key != null)
yield return key.ToString();
}
yield break;
}
var valueType = value.GetType();
var enumerable = value as IEnumerable;
if (enumerable != null)
{
foreach (var item in enumerable)
{
if (item == null)
continue;
valueType = item.GetType();
break;
}
}
foreach (var header in GetHeaders(valueType))
{
yield return header;
}
}
protected internal static IEnumerable<string> GetHeaders(Type valueType)
{
return valueType.GetCachedProperties().Select(x => x.Name);
}
protected internal static IEnumerable<string> GetValues(object value)
{
return value.ToDictionary().ToHashTable().Values;
}
protected internal static IEnumerable<string> ParseHeaders(string source, string delimiter = null)
{
return
source
.Split(new[] { delimiter ?? DefaultDelimiter }, StringSplitOptions.None)
.Select(x => x.Trim('"').Trim());
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
public class CsvReader<T> : CsvReader
{
private readonly Func<IDictionary<string, string>, T> _mapper;
public CsvReader(TextReader reader, Func<IDictionary<string, string>, T> mapper, string delimiter = null)
: base(reader, GetHeaders<T>(), delimiter)
{
_mapper = mapper;
}
public IEnumerable<T> ReadAll()
{
return ReadAllRows(_mapper);
}
}
public class CsvReader : CsvHelper, IDisposable
{
private readonly string _delimiter;
private readonly TextReader _reader;
public IEnumerable<string> Headers { get; private set; }
public CsvReader(TextReader reader, string delimiter = null)
: this(reader, ReadHeaders(reader, delimiter), delimiter)
{
}
public CsvReader(TextReader reader, IEnumerable<string> headers, string delimiter = null)
{
_reader = reader;
Headers = headers;
_delimiter = delimiter ?? DefaultDelimiter;
}
public void Dispose()
{
if(_reader != null)
_reader.Dispose();
}
public IEnumerable<T> ReadAllRows<T>(Func<IDictionary<string, string>, T> mapper)
{
var rows = ReadAllRows();
return rows.Select(mapper);
}
public IEnumerable<IDictionary<string, string>> ReadAllRows()
{
string line;
while((line = _reader.ReadLine()) != null)
{
yield return ReadRow(line);
}
}
public IDictionary<string, string> ReadRow()
{
var line = _reader.ReadLine();
return ReadRow(line);
}
private IDictionary<string, string> ReadRow(string line)
{
if (line == null)
return null;
var values = line.Split(new[] { _delimiter }, StringSplitOptions.None);
return ToKeyValuePairs(values).ToDictionary();
}
public static IEnumerable<string> ReadHeaders(TextReader reader, string delimiter = null)
{
var firstLine = reader.ReadLine();
if (firstLine == null)
return Enumerable.Empty<string>();
return ParseHeaders(firstLine, delimiter ?? DefaultDelimiter);
}
private IEnumerable<KeyValuePair<string, string>> ToKeyValuePairs(string[] values)
{
var idx = 0;
if (Headers.Count() < values.Length)
Trace.TraceError("** Found more values than headers ** ");
foreach (var header in Headers)
{
if (values.Length > idx)
yield return new KeyValuePair<string, string>(header, values[idx]);
else
yield return new KeyValuePair<string, string>(header, string.Empty);
idx += 1;
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public class CsvWriter : CsvHelper, IDisposable
{
private readonly TextWriter _writer;
public string Delimiter { get; private set; }
public bool IncludeTimestamp { get; set; }
public CsvWriter(string filename, string delimiter = null)
: this(new StreamWriter(filename, true), delimiter)
{
}
public CsvWriter(TextWriter writer, string delimiter = null)
{
_writer = writer;
Delimiter = delimiter ?? DefaultDelimiter;
}
public void WriteAll(object value, bool writeHeaders = true)
{
if(value == null)
throw new System.ApplicationException("value");
if (writeHeaders)
{
var headers = GetHeaders(value);
if (IncludeTimestamp)
{
headers = new[] { "Timestamp (UTC)" }.Concat(headers);
}
WriteLine(headers);
}
var rows = GetRows(value);
foreach (var row in rows)
{
var values = row;
if (IncludeTimestamp)
values = new[] { DateTime.UtcNow.ToString("u") }.Concat(values);
WriteLine(values);
}
}
public void WriteLine(IEnumerable<string> values)
{
var line = string.Join(Delimiter, values.Select(Escape));
_writer.WriteLine(line);
}
private IEnumerable<IEnumerable<string>> GetRows(object data)
{
IDictionary<string, string> dictionary;
if (data is IDictionary<string, object>)
{
dictionary = (data as IDictionary<string, object>).ToHashTable();
}
else
{
dictionary = data as IDictionary<string, string>;
}
if (dictionary != null)
{
yield return dictionary.Values;
yield break;
}
var enumerable = data as IEnumerable;
if (enumerable == null)
{
yield return GetValues(data);
yield break;
}
foreach (var value in enumerable)
{
yield return GetValues(value);
}
}
public void Dispose()
{
if (_writer != null)
_writer.Dispose();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment