Created
March 15, 2013 09:50
-
-
Save RhysC/5168701 to your computer and use it in GitHub Desktop.
CSV reader from http://www.thinqlinq.com/default/LINQ-to-CSV-using-DynamicObject.aspx. Ported to c# with basic usage example at the bottom (using xunit). Uses dynamic to provide the field names based on headers. Have changed the default of changing spaces to underscores to just removing them.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Dynamic; | |
using System.Collections.Generic; | |
using System.Collections; | |
using System.IO; | |
using Xunit; | |
namespace YourNamespace | |
{ | |
public class DynamicCsv : DynamicObject | |
{ | |
private readonly Dictionary<string, int> _fieldIndex; | |
private readonly string[] _rowValues; | |
internal DynamicCsv(string currentRow, Dictionary<string, int> fieldIndex) | |
{ | |
_rowValues = currentRow.Split(','); | |
_fieldIndex = fieldIndex; | |
} | |
public override bool TryGetMember(GetMemberBinder binder, out object result) | |
{ | |
if (_fieldIndex.ContainsKey(binder.Name)) | |
{ | |
result = _rowValues[_fieldIndex[binder.Name]]; | |
return true; | |
} | |
result = null; | |
return false; | |
} | |
public override bool TrySetMember(SetMemberBinder binder, object value) | |
{ | |
if (_fieldIndex.ContainsKey(binder.Name)) | |
{ | |
_rowValues[_fieldIndex[binder.Name]] = value.ToString(); | |
return true; | |
} | |
return false; | |
} | |
} | |
public class DynamicCsvEnumerator : IEnumerator<object>, IEnumerable<object> | |
{ | |
private TextReader _fileStream; | |
private Dictionary<string, int> _fieldNames; | |
private DynamicCsv _currentRow; | |
private readonly string _filename; | |
public DynamicCsvEnumerator(string fileName) | |
{ | |
_filename = fileName; | |
} | |
IEnumerator<object> IEnumerable<object>.GetEnumerator() | |
{ | |
_fileStream = new StreamReader(_filename); | |
var headerRow = _fileStream.ReadLine(); | |
if (string.IsNullOrWhiteSpace(headerRow)) | |
throw new InvalidOperationException("Header row must have values"); | |
var fields = headerRow.Split(','); | |
_fieldNames = new Dictionary<string, int>(); | |
for (var i = 0; i <= fields.Length - 1; i++) | |
{ | |
_fieldNames.Add(GetSafeFieldName(fields[i]), i); | |
} | |
return this; | |
} | |
public string GetSafeFieldName(string input) | |
{ | |
return input.Replace(" ", ""); | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
return ((IEnumerable<object>)this).GetEnumerator(); | |
} | |
object IEnumerator<object>.Current | |
{ | |
get { return _currentRow; } | |
} | |
object IEnumerator.Current | |
{ | |
get | |
{ | |
return ((IEnumerator<object>)this).Current; | |
} | |
} | |
bool IEnumerator.MoveNext() | |
{ | |
var line = _fileStream.ReadLine(); | |
if (!string.IsNullOrEmpty(line)) | |
{ | |
_currentRow = new DynamicCsv(line, _fieldNames); | |
return true; | |
} | |
return false; | |
} | |
void IEnumerator.Reset() | |
{ | |
_fileStream.Close(); | |
// ReSharper disable ReturnValueOfPureMethodIsNotUsed | |
((IEnumerable<object>)this).GetEnumerator();//Reopens stream | |
// ReSharper restore ReturnValueOfPureMethodIsNotUsed | |
} | |
public void Dispose() | |
{ | |
_fileStream.Dispose(); | |
} | |
} | |
public class CsvTester | |
{ | |
[Fact] | |
public void doesCsvWork() | |
{ | |
var data = new DynamicCsvEnumerator(@"C:\FileWithNames.csv"); | |
foreach (dynamic item in data) | |
{ | |
Console.WriteLine(item.title + ": " + | |
item.firstName + ": " + | |
item.middleName + ": " + | |
item.lastName); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks!