Read multiple lines with StreamReader with StreamReader.Peek

5k views Asked by At

Let's say I have the following file format (Key value pairs):

Objec1tKey: Object1Value
Object2Key: Object2Value
Object3Key: Object3Value
Object4Key: Object4Value1
Object4Value2
Object4Value3
Object5Key: Object5Value
Object6Key: Object6Value

I'm reading this line by line with StreamReader. for the objects 1, 2, 3, 5 and 6 it wouldn't be a problem because the whole object is on one line, so it's possible to process the object.

But for object 4 I need to process multiple lines. can I use Peek for this? (MSDN for Peek: Returns the next available character but does not consume it.). Is there a method like Peek which returns the next line and not the character?

If I can use Peek, then my question is, can I use Peek two times so I can read the two next lines (or 3) until I know there is a new object (obect 5) to be processed?

3

There are 3 answers

4
Jon Skeet On BEST ANSWER

I would strongly recommend that you separate the IO from the line handling entirely.

Instead of making your processing code use a StreamReader, pass it either an IList<string> or an IEnumerable<string>... if you use IList<string> that will make it really easy to just access the lines by index (so you can easily keep track of "the key I'm processing started at line 5" or whatever), but it would mean either doing something clever or reading the whole file in one go.

If it's not a big file, then just using File.ReadAllLines is going to be the very simplest way of reading a file as a list of lines.

If it is a big file, use File.ReadLines to obtain an IEnumerable<string>, and then your processing code needs to be a bit smarter... for example, it might want to create a List<string> for each key that it processes, containing all the lines for that key - and let that list be garbage collected when you read the next key.

0
Piotr Stapp On

There is now way to use Peek multiple time as you thing, because it will always return only "top" character in stream. It just read it but "not send" to stream information that it was read.

To sum up pointer to stream after Peek stays in same place.

If you use for example FileStream you can use Seek for going back, but you didn't precise what type of stream are you using.

0
Francesco Baruchelli On

You could do something like this:

            List<MyObject> objects = new List<MyObject>();
            using (StreamReader sr = new StreamReader(aPath))
            {
                MyObject curObj;
                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    if (line.IndexOf(':') >= 0) // or whatever identify the beginning of a new object
                    {
                        curObj = new MyObject(line);
                        objects.Add(curObj);
                    }
                    else
                        curObj.AddAttribute(line);
                }
            }