How do you reset a C# .NET TextReader cursor back to the start point?

I have a method that takes either a StringReader instance (reading from the clipboard) or a StreamReader instance (reading from a file) and, at present, casts either one as a TextReader instance.

I need it to 'pre-read' some of the source input, then reset the cursor back to the start. I do not necessarily have the original filename. How to I do this?

There is mention of the Seek method of System.IO.Stream but this is not implemented in TextReader, although it is in StreamReader through the Basestream property. However StringReader does not have a BaseStream property

Answers


It depends on the TextReader. If it's a StreamReader, you can use:

sr.BaseStream.Position = 0;
sr.DiscardBufferedData();

(Assuming the underlying stream is seekable, of course.)

Other implementations of TextReader may not have a concept of "rewinding", in the same way that IEnumerable<T> doesn't. In many ways you can think of TextReader as a glorified IEnumerable<char>. It has methods to read whole chunks of data at a time, read lines etc, but it's fundamentally a "forward reading" type.

EDIT: I don't believe StringReader supports any sort of rewinding - you'd be better off recreating the StringReader from the original string, if you can. If that's not feasible, you could always create your own TextReader class which proxies all the "normal" calls to another StringReader, but recreates that proxy instance when it needs to.


If it is a StreamReader, and if that stream supports seeking, then:

        reader.BaseStream.Seek(0, SeekOrigin.Begin);
        reader.DiscardBufferedData();

However, this is not possible on arbitrary TextReaders. You could perhaps read all of it as a string, then you can use StringReader repeatedly?


I came across your post, and was rather diappointed that this isn't possible. I hacked up something quick which works: just avoid the stringreader altogether:

Stream stream = new MemoryStream((new System.Text.ASCIIEncoding().GetBytes(mystring)), false);
reader = new StreamReader(stream, new System.Text.ASCIIEncoding());

It's not pretty, and it uses ASCII (which was what I needed anyway). Note that with a different encoding this won't work, as you will seek the n'th byte which doesn't have be equal to the n'th character. If you do need that you could do something like

Stream stream = new MemoryStream((new System.Text.UTF32Encoding().GetBytes(mystring)), false);
reader = new StreamReader(stream, new System.Text.UTF32Encoding());

as UTF32 is the only fixed length unicode format.

You can now do

reader.BaseStream.Position = wherever; // or wherever * 4 for the UTF32 variety,
                                       // in your case, the beginning of the string,
                                       // which is always 0 obviously
reader.DiscardBufferedData();

Seek and ye shall find.

Seek(0, SeekOrigin.Begin);

TextReader is derived from StreamReader. StreamReader contains a BaseStream property


Need Your Help

32bit to 64bit inline assembly porting

c++ c assembly 32bit-64bit inline-assembly

I have a piece of C++ code (compiled with g++ under a GNU/Linux environment) that load a function pointer (how it does that doesn't matter), pushes some arguments onto the stack with some inline as...