The use of Seek makes it difficult to use this library with some streams because they do not support seeking (like GZipStream).
Also it seems that if you try to enumerate the result a second time before finishing with the first then both will wind up using the same stream object. I can't see how that could work.
It would be nice if the functions took a sort of StreamReader factory instead of a StreamReader.
public IEnumerable<T> Read<T>(Func<StreamReader> streamFactory)...
public IEnumerable<T> Read<T>(Func<StreamReader> streamFactory, CsvFileDescription fileDescription)...
Then instead of calling Seek the library would just call the factory to get a new StreamReader. This would be much more in keeping with the way the library works when reading files.
For anyone who needs a work around, here is the one I came up with for now. It is kind of horrible and you have to be careful to only use the IEnumerable once.
/// <summary>
/// Workaround for the fact that LINQToCSV tries to rewind the zip stream.
/// This stream has CanSeek == true, but in fact you can only call Seek
/// if to go to the beginning of the file and only when you are already there
/// (have not read any data)
/// </summary>
class LazyRewindGZipStream : GZipStream {
// Keep track of weather we are at the start of the stream
private bool _atStart = true;
public LazyRewindGZipStream(Stream stream, CompressionMode mode)
: base(stream, mode) {}
public override int Read(byte[] array, int offset, int count) {
_atStart = false; // We are not at the start of the stream any more
return base.Read(array, offset, count);
}
public override IAsyncResult BeginRead(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) {
_atStart = false; // We are not at the start of the stream any more
return base.BeginRead(array, offset, count, asyncCallback, asyncState);
}
public override bool CanSeek {
get {
return true; // Permit seek (even though most seeks will be unsupported)
}
}
public override long Seek(long offset, SeekOrigin origin) {
// Only case where we want to allow this
if (offset == 0 && origin == SeekOrigin.Begin && _atStart)
return 0;
// Other wise this is still not supported
return base.Seek(offset, origin);
}
}
The use of Seek makes it difficult to use this library with some streams because they do not support seeking (like GZipStream).
Also it seems that if you try to enumerate the result a second time before finishing with the first then both will wind up using the same stream object. I can't see how that could work.
It would be nice if the functions took a sort of StreamReader factory instead of a StreamReader.
Then instead of calling Seek the library would just call the factory to get a new StreamReader. This would be much more in keeping with the way the library works when reading files.
For anyone who needs a work around, here is the one I came up with for now. It is kind of horrible and you have to be careful to only use the IEnumerable once.