11
votes

How to most efficiently skip some number of bytes in any Stream?

If possible, I'd like to get or throw an EndOfStreamException when trying to skip past the end of the stream.


I am writing a custom stream Reader for ISO 9660 primitive data types, and this may involve a lot of skipping in seekable and non-seekable streams, both small numbers (4) and large numbers (2048) of bytes. Therefore I want to implement a Skip(int count) method that is a bit more efficient than reading and discarding the skipped bytes.

For example, in a seekable stream I might do stream.Position += 4, but this does not throw an EndOfStreamException when seeking past the end of the stream, and I don't know how to test for that without reading something. For non-seekable streams, setting Position is not even an option, but reading and subsequently discarding large numbers of bytes and allocating unused byte arrays seems very wasteful.

1
Frankly, I think what you have described (checking CanSeek and either using Seek or read+discard) is pretty much "it". Maybe you could risk reading .Length in the CanSeek scenario, but: you should exception-handle that too; I'm not sure that CanSeek guarantees a Length implementation.Marc Gravell

1 Answers

11
votes

Instead of stream.Position += 4 you can use stream.Seek(4, SeekOrigin.Current); which saves you one call to Win32 API.

You can always check against the Length property of the stream if it's supported. If it's not supported there isn't a way other than trying to read from the stream. Actually on streams where length is unknown, seeking is essentially reading.

If CanSeek is false, you can't read Length and vice versa.

About wasted memory during reading, you don't have to read amount of bytes you're skipping. You can allocate a fixed size of memory (large or small) and use it for any length you want. If you need to skip more than that size, you just read x / size blocks and read the remainder x % size bytes.