added async reader overloads

This commit is contained in:
Adam Hathcock
2025-10-27 12:23:54 +00:00
parent 1f3d8fe6f1
commit 72d5884db6
3 changed files with 92 additions and 3 deletions

View File

@@ -96,6 +96,33 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader, IReaderExtracti
return false;
}
public async Task<bool> MoveToNextEntryAsync(CancellationToken cancellationToken = default)
{
if (_completed)
{
return false;
}
if (Cancelled)
{
throw new ReaderCancelledException("Reader has been cancelled.");
}
if (_entriesForCurrentReadStream is null)
{
return LoadStreamForReading(RequestInitialStream());
}
if (!_wroteCurrentEntry)
{
await SkipEntryAsync(cancellationToken).ConfigureAwait(false);
}
_wroteCurrentEntry = false;
if (NextEntryForCurrentStream())
{
return true;
}
_completed = true;
return false;
}
protected bool LoadStreamForReading(Stream stream)
{
_entriesForCurrentReadStream?.Dispose();
@@ -129,6 +156,14 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader, IReaderExtracti
}
}
private async Task SkipEntryAsync(CancellationToken cancellationToken)
{
if (!Entry.IsDirectory)
{
await SkipAsync(cancellationToken).ConfigureAwait(false);
}
}
private void Skip()
{
var part = Entry.Parts.First();
@@ -151,6 +186,33 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader, IReaderExtracti
s.SkipEntry();
}
private async Task SkipAsync(CancellationToken cancellationToken)
{
var part = Entry.Parts.First();
if (!Entry.IsSplitAfter && !Entry.IsSolid && Entry.CompressedSize > 0)
{
//not solid and has a known compressed size then we can skip raw bytes.
var rawStream = part.GetRawStream();
if (rawStream != null)
{
var bytesToAdvance = Entry.CompressedSize;
await rawStream.SkipAsync(bytesToAdvance, cancellationToken).ConfigureAwait(false);
part.Skipped = true;
return;
}
}
//don't know the size so we have to try to decompress to skip
#if NETFRAMEWORK || NETSTANDARD2_0
using var s = await OpenEntryStreamAsync(cancellationToken).ConfigureAwait(false);
await s.SkipEntryAsync(cancellationToken).ConfigureAwait(false);
#else
await using var s = await OpenEntryStreamAsync(cancellationToken).ConfigureAwait(false);
await s.SkipEntryAsync(cancellationToken).ConfigureAwait(false);
#endif
}
public void WriteEntryTo(Stream writableStream)
{
if (_wroteCurrentEntry)
@@ -232,6 +294,19 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader, IReaderExtracti
return stream;
}
public Task<EntryStream> OpenEntryStreamAsync(CancellationToken cancellationToken = default)
{
if (_wroteCurrentEntry)
{
throw new ArgumentException(
"WriteEntryToAsync or OpenEntryStreamAsync can only be called once."
);
}
var stream = GetEntryStream();
_wroteCurrentEntry = true;
return Task.FromResult(stream);
}
/// <summary>
/// Retains a reference to the entry stream, so we can check whether it completed later.
/// </summary>

View File

@@ -39,9 +39,23 @@ public interface IReader : IDisposable
/// <returns></returns>
bool MoveToNextEntry();
/// <summary>
/// Moves to the next entry asynchronously by reading more data from the underlying stream. This skips if data has not been read.
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<bool> MoveToNextEntryAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Opens the current entry as a stream that will decompress as it is read.
/// Read the entire stream or use SkipEntry on EntryStream.
/// </summary>
EntryStream OpenEntryStream();
/// <summary>
/// Opens the current entry asynchronously as a stream that will decompress as it is read.
/// Read the entire stream or use SkipEntry on EntryStream.
/// </summary>
/// <param name="cancellationToken"></param>
Task<EntryStream> OpenEntryStreamAsync(CancellationToken cancellationToken = default);
}

View File

@@ -335,9 +335,9 @@
"net8.0": {
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "B3etT5XQ2nlWkZGO2m/ytDYrOmSsQG1XNBaM6ZYlX5Ch/tDrMFadr0/mK6gjZwaQc55g+5+WZMw4Cz3m8VEF7g=="
"requested": "[8.0.18, )",
"resolved": "8.0.18",
"contentHash": "OiXqr2YIBEV9dsAWEtasK470ALyJ0VxJ9k4MotOxlWV6HeEgrJKYMW4HHj1OCCXvqE0/A25wEKPkpfiBARgDZA=="
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",