Open jozkee opened 1 year ago
Tagging subscribers to this area: @dotnet/area-system-io See info in area-owners.md if you want to be subscribed.
Author: | Jozkee |
---|---|
Assignees: | - |
Labels: | `api-suggestion`, `area-System.IO` |
Milestone: | - |
Would it make sense for the constructor to take an offset rather than seeking manually?
Would the wrapper stream verify before each operation that the offset of the underlying stream didn't get moved underneath it? Would that throw?
Would it make sense for the constructor to take an offset rather than seeking manually?
If we do that, that .ctor would be useless for unseekable streams. Not saying that's a bad thing, though.
Would the wrapper stream verify before each operation that the offset of the underlying stream didn't get moved underneath it?
We could do it or we couldn't, even perhaps we could have a bool arg (ensurePosition
) that specifies which behavior a user wants.
I looked at BufferedStream to see how it reacts to the base stream moving, and it does not validate it. Same with other streams. Although, the internal SubReadStream used in System.IO.Compression does adjust the position each time Read
is called.
https://github.com/dotnet/runtime/blob/d3f7d59e8dc44e5ce22c8ec9c011a1b72d7e9e92/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipCustomStreams.cs#L292-L293
We're moving this out to Future and it will be considered again for .NET 9.
Background and motivation
It is generally useful to have a Stream wrapper for read/write a specific part of a larger Stream, and it would be beneficial to provide an implementation that can be easily used and improved.
There has been multiple request asking for such a type, see https://stackoverflow.com/a/30494628/4231460. It also came up on the Twitter survey that @adamsitnik posted: https://github.com/dotnet/runtime/issues/58216#issuecomment-1105445805.
Additionally, we currently have similar internal implementations that read a portion of a stream. https://github.com/dotnet/runtime/blob/d3f7d59e8dc44e5ce22c8ec9c011a1b72d7e9e92/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipCustomStreams.cs#L221
https://github.com/dotnet/runtime/blob/d3f7d59e8dc44e5ce22c8ec9c011a1b72d7e9e92/src/libraries/System.Formats.Tar/src/System/Formats/Tar/SubReadStream.cs#L15
API Proposal
Notes
I considered having a
bool leaveOpen
flag but it seems to me that most of the time you create a substream, you are not done working with the base stream and hence, you will almost never useleaveOpen = false
.Having the
canWrite
parameter is useful because you may want to pass the SubStream as read-only where the baseStream supports writing. This is how the SubReadStream in IO.Compression currently works.I sketched a simple implementation of this proposal and used it to replace internal SubReadStream on System.Formats.Tar and System.IO.Compression. While it could be feasible to completely replace the internal types with this one, they have implementation details that will need to be removed if we want to use this more-generic type. e.g:
HasReachedEnd
property and it throwsEndOfStreamException
when superStream advances to next entry. This is an implementation detail we don't want to expose in this API.NotSupportedException
when attempting to write/flush/seek the SubStream (the base stream does support it). Throwing on write can be addressed by thebool canWrite
param in the ctor but I'm not sure if we want to exposebool canSeek
andbool canFlush
as well.API Usage
Pass a subset of your current stream without buffereing.
Alternative Design 1
Use a factory e.g:
Alternative Design 2
Having a
length
parameter for aDelegatingStream.ctor
could be an alternative to having a fully-fledged SubStream implementation but that would overload (even more) the proposal in https://github.com/dotnet/runtime/issues/43139.Risks
I'm not sure how a Seek operation on a
SubStream
should work. The guideline in theStream
docs is "Seeking to any location beyond the length of the stream is supported". But it appears to me that allowing seeking past the specified lenght may result in a pit of failure, but let me know what you think.