0

I wrote below code, which works:

//VERSION 1;
static IEnumerable<string> ReadAsLines(string filename)
{
    using (StreamReader reader = new StreamReader(filename))
    {
        while (!reader.EndOfStream)
            yield return reader.ReadLine();
    }
}

Using above method:

const string fileData = @"path\to\somePipeDelimitedData.txt";
var reader = ReadAsLines(fileData); 
var headerArr = reader.First().Split('|');
foreach (var column in headerArr)
{
    var dummy = column;
}
var recordsEnumerable = reader.Skip(1); //skip first header Line
//Read other lines...
foreach (var record in recordsEnumerable)
{
    //read each line
    var rowArray = record.Split('|');
    //etc...
}

Now suppose I start off with a Stream instead of a file; I tried re-writing the above code, but am struggling with the stream getting closed. How can I fix the version below?

//VERSION 2;
static IEnumerable<string> ReadAsLines(Stream stream)
{
    using (StreamReader reader = new StreamReader(stream))
    {
        while (!reader.EndOfStream)
            yield return reader.ReadLine();
    }
}

Calling version 2:

byte[] dataByteArr = File.ReadAllBytes(fileData);
MemoryStream memStr = new MemoryStream(dataByteArr);

var reader2 = ReadAsLines(memStr);
var headerArr2 = reader2.First().Split('|'); //*** STREAM gets closed after this line
foreach (var column in headerArr2)
{
    var dummy = column;
}

var recordsEnumerable2 = reader2.Skip(1); //skip first header Line

//Read other lines... *** ERROR OCCURS HERE, as the Stream is closed.
foreach (var record in recordsEnumerable2)
{
    //read each line
    var rowArray = record.Split('|');
    //etc...
}
joedotnot
  • 4,810
  • 8
  • 59
  • 91
  • @Progman it is not duplicate of this question ... [He is asking why `reader2.First()` is causing dispose](https://dotnetfiddle.net/LH0Nqv) – Selvin Jul 16 '21 at 15:21
  • @Selvin Exactly, I know the stream is getting closed, my question is why, and how to re-organize my example with the yield keyword such that it can be used with a Stream. – joedotnot Jul 16 '21 at 15:24
  • 2
    "my question is why" - that doesn't appear anywhere in your question. It's because you're calling `reader2.First()`, which will dispose of the iterator created for the enumerable it's called on. – Jon Skeet Jul 16 '21 at 15:27
  • you may try to iterate it only once ... with the flag which points if it's first row – Selvin Jul 16 '21 at 15:32
  • Thanks everyone for the hints I arrived at a solution. – joedotnot Jul 16 '21 at 16:31

1 Answers1

-1

I re-organized my initial attempt by pulling the StreamReader out of the Enumerable method and disposing it outside when I'm really done.

byte[] dataByteArr = File.ReadAllBytes(fileData); //decoded bytes
var memStr = new MemoryStream(dataByteArr);

using (StreamReader sr = new StreamReader(memStr))
{
    var dataAsEnumerable = ReadAsLines(sr, memStr);
    var headerArr2 = dataAsEnumerable.First().Split('|'); 
    //*** HA! stream is still open !
    foreach (var column in headerArr2)
    {
        var dummy = column;
    }
    var dataMinusHeader = dataAsEnumerable.Skip(1);

    //Read other lines...
    foreach (var record in dataMinusHeader)
    {
        //read each line
        var rowArray = record.Split('|');
        //etc...
    }
}
joedotnot
  • 4,810
  • 8
  • 59
  • 91