I agree. Having to calculate the size of the final buffer makes ordinary chunked reading unnecessarily awkward.
My proposal is to change ReadBytes(byteCount) so it returns fewer bytes when it reaches EOF. For example, requesting 4,096 bytes when only 100 remain would return a MemoryBlock containing those 100 bytes. Reading again at EOF would return an empty MemoryBlock. ReadBytesAsync would behave the same way.
I will also add two methods for cases where the complete requested amount is required:
ReadBytesExactly(byteCount)
ReadBytesExactlyAsync(byteCount)
These would throw an IOException if EOF prevents them from reading the full amount. They would be useful when reading a fixed-size header or record where missing bytes indicate truncated data.
Primitive reads such as ReadInt32 would continue to throw when there are insufficient bytes. Closed streams and actual I/O errors would also continue to raise exceptions.
This changes the existing EOF behaviour, so code that currently relies on ReadBytes throwing for incomplete data would need to use ReadBytesExactly instead. I’ve logged the proposal, including tests for both versions and documentation explaining the change.