Created
May 1, 2014 03:33
-
-
Save meisinger/5a27dc0f51bf6f3162a7 to your computer and use it in GitHub Desktop.
example of a simple csv reader
This file contains hidden or 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
public sealed class CsvReader : IDisposable | |
{ | |
private const char DefaultFieldChar = ','; | |
private const char DefaultQuoteChar = '"'; | |
private const char DefaultEscapeChar = '\\'; | |
private readonly List<CsvLine> collection; | |
private readonly StringBuilder buffer; | |
private readonly Stream stream; | |
private readonly StreamReader reader; | |
private readonly char fieldChar; | |
private readonly char quoteChar; | |
private readonly char escapeChar; | |
private readonly int skipToData; | |
private bool skippedToData; | |
private bool hasMoreData; | |
private int lineNumber; | |
public bool HasDataToRead | |
{ | |
get { return hasMoreData; } | |
} | |
public CsvReader(Stream stream, char fieldChar, char quoteChar, char escapeChar, int skipToData) | |
{ | |
this.stream = stream; | |
this.fieldChar = fieldChar; | |
this.quoteChar = quoteChar; | |
this.escapeChar = escapChar; | |
this.skipToData = skipToData; | |
reader = new StreamReader(stream); | |
buffer = new StringBuilder(); | |
collection = new List<CsvLine>(); | |
hasMoreData = true; | |
} | |
public void Dispose() | |
{ | |
reader.Close(); | |
reader.Dispose(); | |
} | |
public IEnumerable<CsvLine> ReadToEnd() | |
{ | |
while (hasMoreData) | |
{ | |
var tokens = Read(); | |
if (tokens != null) | |
collection.Add(tokens); | |
} | |
return collection; | |
} | |
public CsvLine Read() | |
{ | |
var line = GetNextLine(); | |
if (hasMoreData) | |
return new CsvLine { | |
LineNumber = lineNumber, | |
Line = ParseLine(line) | |
}; | |
return null; | |
} | |
private string GetNextLine() | |
{ | |
if (!skippedToData) | |
{ | |
for (var index = 0; index < skipToData; index++) | |
{ | |
lineNumber++; | |
reader.ReadLine(); | |
} | |
skippedToData = true; | |
} | |
var line = reader.ReadLine(); | |
if (line == null) | |
hasMoreData = false; | |
else | |
lineNumber++; | |
return line; | |
} | |
private string[] ParseLine(string line) | |
{ | |
if (line == null) | |
return new string[0]; | |
var tokens = new List<string>(); | |
var inQuotes = false; | |
buffer.Length = 0; | |
do | |
{ | |
if (inQuotes) | |
{ | |
buffer.Append('\n'); | |
line = GetNextLine(); | |
if (line == null) | |
break; | |
} | |
var lineChars = line.ToCharArray(); | |
for (var index = 0; index < lineChars.Length; index++) | |
{ | |
var lineChar = lineChars[index]; | |
var skipped = false; | |
var escaped = false; | |
var incremented = false; | |
if (lineChar.Equals(escapeChar)) | |
{ | |
lineChar = lineChars[index + 1]; | |
escaped = true; | |
incremented = true; | |
} | |
if (lineChar.Equals(quoteChar)) | |
{ | |
if (!escaped) | |
{ | |
skipped = true; | |
inQuotes = !inQuotes; | |
} | |
} | |
else if ((lineChar.Equals(fieldChar)) && !inQuotes) | |
{ | |
tokens.Add(buffer.ToString().Trim()); | |
buffer.Length = 0; | |
continue; | |
} | |
if (!skipped) | |
buffer.Append(lineChar); | |
if (incremented) | |
index++; | |
} | |
} while (inQuotes); | |
tokens.Add(buffer.ToString().Trim()); | |
return tokens.ToArray(); | |
} | |
public sealed class CsvLine | |
{ | |
private string[] collection; | |
public string this[int index] | |
{ | |
get | |
{ | |
if (index >= collection.Length) | |
return string.Empty; | |
return collection[index]; | |
} | |
} | |
public int Length | |
{ | |
get | |
{ | |
if (collection == null) | |
return 0; | |
return collection.Length; | |
} | |
} | |
public string[] Line | |
{ | |
get { return collection; } | |
set { collection = value; } | |
} | |
public int LineNumber { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment