mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-25 08:24:58 +00:00
Use BufferedStream for async reading in AsyncBinaryReader
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
This commit is contained in:
@@ -6,12 +6,31 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public sealed class AsyncBinaryReader(Stream stream, bool leaveOpen = false) : IDisposable
|
||||
public sealed class AsyncBinaryReader : IDisposable
|
||||
{
|
||||
private readonly Stream _stream = stream ?? throw new ArgumentNullException(nameof(stream));
|
||||
private readonly Stream _stream;
|
||||
private readonly Stream _originalStream;
|
||||
private readonly bool _leaveOpen;
|
||||
private readonly byte[] _buffer = new byte[8];
|
||||
private bool _disposed;
|
||||
|
||||
public AsyncBinaryReader(Stream stream, bool leaveOpen = false, int bufferSize = 4096)
|
||||
{
|
||||
_originalStream = stream ?? throw new ArgumentNullException(nameof(stream));
|
||||
_leaveOpen = leaveOpen;
|
||||
|
||||
// Wrap the stream with BufferedStream if it's not already a buffered stream
|
||||
// This enables efficient async reading with internal buffering
|
||||
if (stream is BufferedStream || stream is IO.SharpCompressStream)
|
||||
{
|
||||
_stream = stream;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream = new BufferedStream(stream, bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream BaseStream => _stream;
|
||||
|
||||
public async ValueTask<byte> ReadByteAsync(CancellationToken ct = default)
|
||||
@@ -31,6 +50,7 @@ namespace SharpCompress.Common
|
||||
await ReadExactAsync(_buffer, 0, 4, ct).ConfigureAwait(false);
|
||||
return BinaryPrimitives.ReadUInt32LittleEndian(_buffer);
|
||||
}
|
||||
|
||||
public async ValueTask<ulong> ReadUInt64Async(CancellationToken ct = default)
|
||||
{
|
||||
await ReadExactAsync(_buffer, 0, 8, ct).ConfigureAwait(false);
|
||||
@@ -44,12 +64,19 @@ namespace SharpCompress.Common
|
||||
return result;
|
||||
}
|
||||
|
||||
private async ValueTask ReadExactAsync(byte[] destination, int offset, int length, CancellationToken ct)
|
||||
private async ValueTask ReadExactAsync(
|
||||
byte[] destination,
|
||||
int offset,
|
||||
int length,
|
||||
CancellationToken ct
|
||||
)
|
||||
{
|
||||
var read = 0;
|
||||
while (read < length)
|
||||
{
|
||||
var n = await _stream.ReadAsync(destination, offset + read, length - read, ct).ConfigureAwait(false);
|
||||
var n = await _stream
|
||||
.ReadAsync(destination, offset + read, length - read, ct)
|
||||
.ConfigureAwait(false);
|
||||
if (n == 0)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
@@ -61,27 +88,47 @@ namespace SharpCompress.Common
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed || leaveOpen)
|
||||
if (_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
_stream.Dispose();
|
||||
|
||||
// Dispose the buffered stream if we created it
|
||||
if (_stream != _originalStream)
|
||||
{
|
||||
_stream.Dispose();
|
||||
}
|
||||
|
||||
// Dispose the original stream if we own it
|
||||
if (!_leaveOpen)
|
||||
{
|
||||
_originalStream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
public ValueTask DisposeAsync()
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_disposed || leaveOpen)
|
||||
if (_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
return default;
|
||||
return;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
return _stream.DisposeAsync();
|
||||
|
||||
// Dispose the buffered stream if we created it
|
||||
if (_stream != _originalStream)
|
||||
{
|
||||
await _stream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Dispose the original stream if we own it
|
||||
if (!_leaveOpen)
|
||||
{
|
||||
await _originalStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user