Skip to content

BinaryReader.PeekChar causes excessive reads in underlying Stream if used with BufferedStream #54593

@lekrus

Description

@lekrus

Description

When BinaryReader.PeekChar is called multiple times for BufferedStream it will cause read of full buffer with each call.
Sample reproduce:

public class CustomStream : Stream {
	private readonly FileStream _fileStream;
	public CustomStream(FileStream fileStream) {
		_fileStream = fileStream;
	}
	public override int Read(byte[] buffer, int offset, int count) {
		Console.WriteLine("Read: count: {0}, pos: {1}, len: {2}, off: {3}", count, Position, Length, offset);
		return _fileStream.Read(buffer, offset, count);
	}
// other methods are skipped for brevity
}

static void Main(string[] args) {
	using var input = new BinaryReader(new BufferedStream(new CustomStream(File.Open("test.rtf", FileMode.Open))));
	
	for (int i = 0; i < 3; i++) {
		input.PeekChar();
	}
}

Running that code will output:

Read: count: 4096, pos: 0, len: 55355, off: 0
Read: count: 4096, pos: 0, len: 55355, off: 0
Read: count: 4096, pos: 0, len: 55355, off: 0

It shows that underlying stream is called to read full buffer (in our case 4096 is a default buffer, but with bigger buffer size it becomes even more prominent)

Analysis

From what I see, the issue occurs when PeekChar restores it's position:

long origPos = _stream.Position;
int ch = Read();
_stream.Position = origPos;

and setting Position in BufferedStream resets data in read buffer:

if (_writePos > 0)
FlushWrite();

_readPos = 0;
_readLen = 0; // <-- resetting read buffer
_stream!.Seek(value, SeekOrigin.Begin);

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions