4

For a C# project i am using streamreader, i need to go back 1 character (basicly like undoing) and i need it to change so when you get the next character it is the same one as when you rolled back

For example

Hello There

we do

H

E

L

L

O

[whitespace]

T

H

E

R <-- we undo the R

so..

R <-- undid

R

E

that is a rough idea

Steven
  • 41
  • 3
  • i think it isn't possible as when you read a stream, it returns and advances, and that's gone. it is maybe possible with files and memory streams, but think of a network stream. you read the data, and it's incoming, it's processed and gone forever, it's not "stored" somewhere. but if you SPECIFICALLY want this for, e.g., memory streams, you may go unsafe code and do some pointer arithmetic and i *think* it should work.. – Can Poyrazoğlu Aug 13 '11 at 08:38

3 Answers3

2

When you don't know if you want the value, instead of Read(), use Peek() - then you can check the value without advancing the stream. Another approach (that I use in some of my code) is to encapsulate the reader (or in my case, a Stream) in a class that has an internal buffer that lets you push values back. The buffer is always used first, making it easy to push values (or even: adjusted values) back into the stream without having to rewind it (which doesn't work for a number of streams).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

A clean solution would be to derive a class from StreamReader and override the Read() function.

For your requirements a simple private int lastChar would suffice to implement a Pushback() method. A more general solution would use a Stack<char> to allow unlimited pushbacks.

//untested, incomplete
class MyReader : StreamReader
{
    public MyReader(Stream strm)
        : base(strm)
    {
    }

    private int lastChar = -1;
    public override int Read()
    {
        int ch;

        if (lastChar >= 0)
        {
            ch = lastChar;
            lastChar = -1;
        }
        else
        {
            ch = base.Read();  // could be -1 
        }
        return ch;
    }

    public void PushBack(char ch)  // char, don't allow Pushback(-1)
    {
        if (lastChar >= 0) 
          throw new InvalidOperation("PushBack of more than 1 char");

        lastChar = ch;
    }
}
H H
  • 263,252
  • 30
  • 330
  • 514
-3

Minus one from the position:

var bytes = Encoding.ASCII.GetBytes("String");
Stream stream = new MemoryStream(bytes);
Console.WriteLine((char)stream.ReadByte()); //S
Console.WriteLine((char)stream.ReadByte()); //t
stream.Position -= 1;
Console.WriteLine((char)stream.ReadByte()); //t
Console.WriteLine((char)stream.ReadByte()); //r
Console.WriteLine((char)stream.ReadByte()); //i
Console.WriteLine((char)stream.ReadByte()); //n
Console.WriteLine((char)stream.ReadByte()); //g
Ryan Andres
  • 312
  • 3
  • 13
  • For the StreamReader, access its BaseStream property and set its Position. – Ryan Andres Aug 13 '11 at 08:46
  • Not all streams have CanSeek() == true. – H H Aug 13 '11 at 08:57
  • Bear in mind that the Position property is only supported by some stream implementations, e.g. NetworkStream *doesn't* support it. Use the stream's CanSeek property to determine if it's possible. – Stu Mackellar Aug 13 '11 at 09:00
  • 2
    -1 for 3 reasons: a: byte != character, b: question was `StreamReader`, c: not all streams are seekable – Marc Gravell Aug 13 '11 at 09:07
  • 2
    @Ryan - also, re "access its BaseStream" - if you do that, you need to worry about the reader's buffer too - and again, not all streams are seekable (it is always best to avoid seek if possible) – Marc Gravell Aug 13 '11 at 09:42