patterncsharpMinor
CSV writer implementation
Viewed 0 times
writerimplementationcsv
Problem
I've recently been assigned to write up a CSV writer with "as much flexibility" as possible concerning pretty much all (output stream, string fields with potential new line characters, separator collisions, etc. you name it...)
No specification, no design guidelines, no nothing and I'm not expecting any any time soon (let's not dwell on the situation I'm currently in...). So, I've quickly built a test implementation which is as follows:
```
public sealed class CsvWriter : MarshalByRefObject, IDisposable
{
private const int MIN_BUFFER = 8;
private const char ESCAPE_CHAR = '\\';
private const char ESCAPED_SEPARATOR_CHAR = 's';
private Stream output;
private readonly StringBuilder buffer;
private bool isDisposed;
private readonly IEnumerable> projections;
private readonly List ignoredCharacters;
private readonly char listSeparator;
private readonly bool escapeListSeparator;
private readonly Encoding encoding;
private readonly bool escapeNewLineCharacters;
private readonly int bufferLength = 512;
public CsvWriter(Stream output, IEnumerable> projections, Encoding encoding = null, int bufferLength = 512, bool escapeListSeparatorInsideFields = true,
bool escapeNewLineCharacters = true, IEnumerable ignoredCharacters = null)
: this(output, projections, CultureInfo.CurrentCulture.TextInfo.ListSeparator[0], encoding, bufferLength, escapeListSeparatorInsideFields, escapeNewLineCharacters, ignoredCharacters)
{
}
public CsvWriter(Stream output, IEnumerable> projections, char listSeparator, Encoding encoding = null, int bufferLength = 512, bool escapeListSeparatorInsideFields = true,
bool escapeNewLineCharacters = true, IEnumerable ignoredCharacters = null)
{
ArgumentValidator.ArgumentNotNull(output, "output");
ArgumentValidator.ArgumentNotNull(projections, "projections");
ArgumentValidator.ArgumentNotValid(output, b => output.CanWrite, "output", "Can not wri
No specification, no design guidelines, no nothing and I'm not expecting any any time soon (let's not dwell on the situation I'm currently in...). So, I've quickly built a test implementation which is as follows:
```
public sealed class CsvWriter : MarshalByRefObject, IDisposable
{
private const int MIN_BUFFER = 8;
private const char ESCAPE_CHAR = '\\';
private const char ESCAPED_SEPARATOR_CHAR = 's';
private Stream output;
private readonly StringBuilder buffer;
private bool isDisposed;
private readonly IEnumerable> projections;
private readonly List ignoredCharacters;
private readonly char listSeparator;
private readonly bool escapeListSeparator;
private readonly Encoding encoding;
private readonly bool escapeNewLineCharacters;
private readonly int bufferLength = 512;
public CsvWriter(Stream output, IEnumerable> projections, Encoding encoding = null, int bufferLength = 512, bool escapeListSeparatorInsideFields = true,
bool escapeNewLineCharacters = true, IEnumerable ignoredCharacters = null)
: this(output, projections, CultureInfo.CurrentCulture.TextInfo.ListSeparator[0], encoding, bufferLength, escapeListSeparatorInsideFields, escapeNewLineCharacters, ignoredCharacters)
{
}
public CsvWriter(Stream output, IEnumerable> projections, char listSeparator, Encoding encoding = null, int bufferLength = 512, bool escapeListSeparatorInsideFields = true,
bool escapeNewLineCharacters = true, IEnumerable ignoredCharacters = null)
{
ArgumentValidator.ArgumentNotNull(output, "output");
ArgumentValidator.ArgumentNotNull(projections, "projections");
ArgumentValidator.ArgumentNotValid(output, b => output.CanWrite, "output", "Can not wri
Solution
- You should use auto-properties instead of
public IEnumerable IgnoredCharacters
{
get
{
return this.ignoredCharacters;
}
}It will improve the readability of your code.
-
The recommended naming convention for constants in
.Net is Pascal case. So it should be MinBuffer, for example. Same goes for methods (CheckBuffer()).-
Instead of manually moving your iterator, you should use a
foreach loop.-
Your
WriteLine method is too complex. You should probably break it down to smaller parts, so it's easier to understand. I would also encapsulate parsing logic into different class.-
Your constructor is too complex as well, you should encapsulate those parameters into some class (
CswWriterSettings?).-
BufferedStream and StreamWriter classes (even Stream class to some degree) cache data internally. I suggest you use either of those classes instead of building and maintaining your own cache. Edit: Actually, FileStream already has an internal buffer, so there is no point in using BufferedStream either. It will only result in double buffering.-
I did not quite understand what
projection is, so I'm not sure if it's really needed, but in my experience - passing a delegate to a constructor (let alone a collection of delegates) is almost always a bad idea. :)Code Snippets
public IEnumerable<char> IgnoredCharacters
{
get
{
return this.ignoredCharacters;
}
}Context
StackExchange Code Review Q#69829, answer score: 5
Revisions (0)
No revisions yet.