This is a fairly artificial example, but demonstrates how peeking/read-behind might be used to read a custom data format. Here we assume that we are reading 7- or 63-bit offsets, differentiated by the lowest bit (this example only works on little-endian machines such as the x86/x64--a big-endian machine would use the highest bit as the flag in a similar fashion). We first read a byte and check if its lowest bit--if it's 0, we're done, but otherwise we move one byte backwards to our original position and then read a long (effectively having "peeked" at the next byte). The code then seeks ahead this many bytes and repeats the process until an offset of 0 is read.
Because we use a read-behind of 1 byte with the BetterBufferedStream, we know that, after reading a byte, it is always preserved in the buffer and we can move back efficiently, without having to manipulate the underlying stream. We also avoid this when we seek forward to a location already buffered--this can be compared to BufferedStream or FileStream which will always seek on the underlying stream and wholly refill the buffer after any repositioning. Even a few seeks on these streams can be significant performance hit if the buffer is reasonably large.
The following performance was observed when reading every other kilobyte (alternating between reading 1024 bytes and advancing the stream position by 1024) of a 4GB file [testing methodology]:

With a 100KB buffer BufferedStream and FileStream refill the buffer fifty times every 100KB, reading every byte from the underlying stream approximately fifty times (compared to once for AsyncStream and BetterBufferedStream); their performance is worse with larger buffers or more frequent seeks. Because the disk performs its own caching the 100KB BufferedStream and FileStream do not actually take fifty times as long, but this mitigating factor not present when reading other types of streams.
using System; using System.IO; using BetterStreams; namespace BetterStreamsExamples { public static class StreamJumper { public static void Jump(Stream stream) { //create a BetterBufferedStream with a read-behind of 1 and a 100KB buffer BetterBufferedStream bbs = new BetterBufferedStream(stream, 102400, 1); BinaryReader reader = new BinaryReader(bbs); while (true) { long offset = reader.ReadByte(); if ((offset & 1) == 1) //we should read a 64-bit, not 8-bit, value { bbs.Position--; offset = reader.ReadInt64(); } //bitshift to remove flag bit offset >>= 1; //stop when we find an offset of 0 if (offset == 0) break; //jump ahead bbs.Position += offset; } } } } |