mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-23 23:45:14 +00:00
read async interface for reader
This commit is contained in:
@@ -133,6 +133,7 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
|
||||
}
|
||||
|
||||
protected abstract IReader CreateReaderForSolidExtraction();
|
||||
protected abstract ValueTask<IReaderAsync> CreateReaderForSolidExtractionAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
|
||||
@@ -191,7 +192,7 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
|
||||
|
||||
public IAsyncEnumerable<IVolume> VolumesAsync => _lazyVolumesAsync.Cast<TVolume, IVolume>();
|
||||
|
||||
public async ValueTask<IReader> ExtractAllEntriesAsync()
|
||||
public async ValueTask<IReaderAsync> ExtractAllEntriesAsync()
|
||||
{
|
||||
if (!IsSolid && Type != ArchiveType.SevenZip)
|
||||
{
|
||||
@@ -203,9 +204,6 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveAsync
|
||||
return await CreateReaderForSolidExtractionAsync();
|
||||
}
|
||||
|
||||
protected virtual ValueTask<IReader> CreateReaderForSolidExtractionAsync() =>
|
||||
new(CreateReaderForSolidExtraction());
|
||||
|
||||
public virtual ValueTask<bool> IsSolidAsync() => new(false);
|
||||
|
||||
public async ValueTask<bool> IsCompleteAsync()
|
||||
|
||||
@@ -336,4 +336,11 @@ public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
|
||||
stream.Position = 0;
|
||||
return GZipReader.Open(stream);
|
||||
}
|
||||
|
||||
protected override ValueTask<IReaderAsync> CreateReaderForSolidExtractionAsync()
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new(GZipReader.Open(stream));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public interface IArchiveAsync : IAsyncDisposable
|
||||
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
|
||||
/// extracted sequentially for the best performance.
|
||||
/// </summary>
|
||||
ValueTask<IReader> ExtractAllEntriesAsync();
|
||||
ValueTask<IReaderAsync> ExtractAllEntriesAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
|
||||
|
||||
@@ -30,7 +30,7 @@ public static class IArchiveAsyncExtensions
|
||||
// For solid archives (Rar, 7Zip), use the optimized reader-based approach
|
||||
if (await archive.IsSolidAsync() || archive.Type == ArchiveType.SevenZip)
|
||||
{
|
||||
using var reader = await archive.ExtractAllEntriesAsync();
|
||||
await using var reader = await archive.ExtractAllEntriesAsync();
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
destinationDirectory,
|
||||
options,
|
||||
|
||||
@@ -67,7 +67,13 @@ public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
|
||||
return new StreamRarArchiveVolume(sourceStream, ReaderOptions, i++).AsEnumerable();
|
||||
}
|
||||
|
||||
protected override IReader CreateReaderForSolidExtraction()
|
||||
protected override IReader CreateReaderForSolidExtraction() =>
|
||||
CreateReaderForSolidExtractionInternal();
|
||||
|
||||
protected override ValueTask<IReaderAsync> CreateReaderForSolidExtractionAsync() =>
|
||||
new(CreateReaderForSolidExtractionInternal());
|
||||
|
||||
private RarReader CreateReaderForSolidExtractionInternal()
|
||||
{
|
||||
if (this.IsMultipartVolume())
|
||||
{
|
||||
|
||||
@@ -265,6 +265,9 @@ public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVol
|
||||
protected override IReader CreateReaderForSolidExtraction() =>
|
||||
new SevenZipReader(ReaderOptions, this);
|
||||
|
||||
protected override ValueTask<IReaderAsync> CreateReaderForSolidExtractionAsync() =>
|
||||
new(new SevenZipReader(ReaderOptions, this));
|
||||
|
||||
public override bool IsSolid =>
|
||||
Entries
|
||||
.Where(x => !x.IsDirectory)
|
||||
|
||||
@@ -366,4 +366,11 @@ public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
stream.Position = 0;
|
||||
return TarReader.Open(stream);
|
||||
}
|
||||
|
||||
protected override ValueTask<IReaderAsync> CreateReaderForSolidExtractionAsync()
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new(TarReader.Open(stream));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,4 +592,11 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
((IStreamStack)stream).StackSeek(0);
|
||||
return ZipReader.Open(stream, ReaderOptions, Entries);
|
||||
}
|
||||
|
||||
protected override ValueTask<IReaderAsync> CreateReaderForSolidExtractionAsync()
|
||||
{
|
||||
var stream = Volumes.Single().Stream;
|
||||
stream.Position = 0;
|
||||
return new(ZipReader.Open(stream));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,18 +27,21 @@ namespace SharpCompress.Factories
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
)
|
||||
{
|
||||
return AceHeader.IsArchive(stream);
|
||||
}
|
||||
) => AceHeader.IsArchive(stream);
|
||||
|
||||
public IReader OpenReader(Stream stream, ReaderOptions? options) =>
|
||||
AceReader.Open(stream, options);
|
||||
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReaderAsync> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
) => new(OpenReader(stream, options));
|
||||
) => new(AceReader.Open(stream, options));
|
||||
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => new(IsArchive(stream, password, bufferSize));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,14 +44,16 @@ namespace SharpCompress.Factories
|
||||
public IReader OpenReader(Stream stream, ReaderOptions? options) =>
|
||||
ArcReader.Open(stream, options);
|
||||
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReaderAsync> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new(OpenReader(stream, options));
|
||||
}
|
||||
) => new(ArcReader.Open(stream, options));
|
||||
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => new(IsArchive(stream, password, bufferSize));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,14 +35,16 @@ namespace SharpCompress.Factories
|
||||
public IReader OpenReader(Stream stream, ReaderOptions? options) =>
|
||||
ArjReader.Open(stream, options);
|
||||
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReaderAsync> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new(OpenReader(stream, options));
|
||||
}
|
||||
) => new(ArjReader.Open(stream, options));
|
||||
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => new(IsArchive(stream, password, bufferSize));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,12 @@ public abstract class Factory : IFactory
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
);
|
||||
|
||||
public abstract ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
@@ -106,4 +112,34 @@ public abstract class Factory : IFactory
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal virtual async ValueTask<(bool, IReaderAsync?)> TryOpenReaderAsync(
|
||||
SharpCompressStream stream,
|
||||
ReaderOptions options,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
if (this is IReaderFactory readerFactory)
|
||||
{
|
||||
long pos = ((IStreamStack)stream).GetPosition();
|
||||
|
||||
if (
|
||||
await IsArchiveAsync(
|
||||
stream,
|
||||
options.Password,
|
||||
options.BufferSize,
|
||||
cancellationToken
|
||||
)
|
||||
)
|
||||
{
|
||||
((IStreamStack)stream).StackSeek(pos);
|
||||
return (
|
||||
true,
|
||||
await readerFactory.OpenReaderAsync(stream, options, cancellationToken)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (false, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,12 @@ public class GZipFactory
|
||||
CancellationToken cancellationToken = default
|
||||
) => GZipArchive.OpenAsync(stream, readerOptions, cancellationToken);
|
||||
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => new(IsArchive(stream, password, bufferSize));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
GZipArchive.Open(fileInfo, readerOptions);
|
||||
@@ -147,14 +153,14 @@ public class GZipFactory
|
||||
GZipReader.Open(stream, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReaderAsync> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new(OpenReader(stream, options));
|
||||
return new(GZipReader.Open(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -67,6 +67,12 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade
|
||||
CancellationToken cancellationToken = default
|
||||
) => RarArchive.OpenAsync(fileInfo, readerOptions, cancellationToken);
|
||||
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => new(IsArchive(stream, password, bufferSize));
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMultiArchiveFactory
|
||||
@@ -102,14 +108,14 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade
|
||||
RarReader.Open(stream, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReaderAsync> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new(OpenReader(stream, options));
|
||||
return new(RarReader.Open(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -62,6 +62,12 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
|
||||
CancellationToken cancellationToken = default
|
||||
) => SevenZipArchive.OpenAsync(fileInfo, readerOptions, cancellationToken);
|
||||
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => new(IsArchive(stream, password, bufferSize));
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMultiArchiveFactory
|
||||
|
||||
@@ -61,6 +61,12 @@ public class TarFactory
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => TarArchive.IsTarFile(stream);
|
||||
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => new(IsArchive(stream, password, bufferSize));
|
||||
|
||||
#endregion
|
||||
|
||||
#region IArchiveFactory
|
||||
@@ -265,14 +271,14 @@ public class TarFactory
|
||||
TarReader.Open(stream, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReaderAsync> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new(OpenReader(stream, options));
|
||||
return new(TarReader.Open(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -25,4 +25,10 @@ internal class ZStandardFactory : Factory
|
||||
string? password = null,
|
||||
int bufferSize = 65536
|
||||
) => ZStandardStream.IsZStandard(stream);
|
||||
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => new(IsArchive(stream, password, bufferSize));
|
||||
}
|
||||
|
||||
@@ -81,6 +81,12 @@ public class ZipFactory
|
||||
return false;
|
||||
}
|
||||
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => new(IsArchive(stream, password, bufferSize));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
@@ -189,14 +195,14 @@ public class ZipFactory
|
||||
ZipReader.Open(stream, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReaderAsync> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return new(OpenReader(stream, options));
|
||||
return new(ZipReader.Open(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -12,17 +12,13 @@ namespace SharpCompress.Readers;
|
||||
/// <summary>
|
||||
/// A generic push reader that reads unseekable comrpessed streams.
|
||||
/// </summary>
|
||||
public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
public abstract class AbstractReader<TEntry, TVolume> : IReader, IReaderAsync
|
||||
where TEntry : Entry
|
||||
where TVolume : Volume
|
||||
{
|
||||
private bool _completed;
|
||||
private IEnumerator<TEntry>? _entriesForCurrentReadStream;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the async entry enumerator when the reader is operating in an async-only mode.
|
||||
/// </summary>
|
||||
private IAsyncEnumerator<TEntry>? _asyncEntriesForCurrentReadStream;
|
||||
private IAsyncEnumerator<TEntry>? _entriesForCurrentReadStreamAsync;
|
||||
private bool _wroteCurrentEntry;
|
||||
|
||||
internal AbstractReader(ReaderOptions options, ArchiveType archiveType)
|
||||
@@ -43,19 +39,31 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
/// <summary>
|
||||
/// Current file entry (from either sync or async enumeration).
|
||||
/// </summary>
|
||||
public TEntry Entry =>
|
||||
_entriesForCurrentReadStream?.Current
|
||||
?? _asyncEntriesForCurrentReadStream?.Current
|
||||
?? throw new InvalidOperationException("No current entry is available.");
|
||||
public TEntry Entry
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_entriesForCurrentReadStreamAsync is not null)
|
||||
{
|
||||
return _entriesForCurrentReadStreamAsync.Current;
|
||||
}
|
||||
return _entriesForCurrentReadStream.NotNull().Current;
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
_entriesForCurrentReadStream?.Dispose();
|
||||
if (_asyncEntriesForCurrentReadStream is IDisposable disposable)
|
||||
Volume?.Dispose();
|
||||
}
|
||||
|
||||
public virtual async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_entriesForCurrentReadStreamAsync is not null)
|
||||
{
|
||||
disposable.Dispose();
|
||||
await _entriesForCurrentReadStreamAsync.DisposeAsync();
|
||||
}
|
||||
Volume?.Dispose();
|
||||
}
|
||||
@@ -79,7 +87,7 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
|
||||
public bool MoveToNextEntry()
|
||||
{
|
||||
if (_asyncEntriesForCurrentReadStream is not null)
|
||||
if (_entriesForCurrentReadStreamAsync is not null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(MoveToNextEntry)} cannot be used after {nameof(MoveToNextEntryAsync)} has been used."
|
||||
@@ -120,17 +128,16 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
{
|
||||
throw new ReaderCancelledException("Reader has been cancelled.");
|
||||
}
|
||||
if (_entriesForCurrentReadStream is null && _asyncEntriesForCurrentReadStream is null)
|
||||
if (_entriesForCurrentReadStreamAsync is null)
|
||||
{
|
||||
return await LoadStreamForReadingAsync(RequestInitialStream(), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return await LoadStreamForReadingAsync(RequestInitialStream());
|
||||
}
|
||||
if (!_wroteCurrentEntry)
|
||||
{
|
||||
await SkipEntryAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
_wroteCurrentEntry = false;
|
||||
if (await NextEntryForCurrentStreamAsync(cancellationToken).ConfigureAwait(false))
|
||||
if (await NextEntryForCurrentStreamAsync(cancellationToken))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -140,7 +147,7 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
|
||||
protected bool LoadStreamForReading(Stream stream)
|
||||
{
|
||||
if (_asyncEntriesForCurrentReadStream is not null)
|
||||
if (_entriesForCurrentReadStreamAsync is not null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(LoadStreamForReading)} cannot be used after {nameof(LoadStreamForReadingAsync)} has been used."
|
||||
@@ -159,21 +166,12 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
return _entriesForCurrentReadStream.MoveNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the stream for reading entries asynchronously, using an async entry enumerator when available.
|
||||
/// </summary>
|
||||
protected async Task<bool> LoadStreamForReadingAsync(
|
||||
Stream stream,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
protected async ValueTask<bool> LoadStreamForReadingAsync(Stream stream)
|
||||
{
|
||||
// Always reset the previous async enumerator so that a new stream can be loaded cleanly.
|
||||
if (_asyncEntriesForCurrentReadStream is IDisposable disposable)
|
||||
if (_entriesForCurrentReadStreamAsync is not null)
|
||||
{
|
||||
disposable.Dispose();
|
||||
await _entriesForCurrentReadStreamAsync.DisposeAsync();
|
||||
}
|
||||
_asyncEntriesForCurrentReadStream = null;
|
||||
|
||||
if (stream is null || !stream.CanRead)
|
||||
{
|
||||
throw new MultipartStreamRequiredException(
|
||||
@@ -182,16 +180,8 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
+ "'. A new readable stream is required. Use Cancel if it was intended."
|
||||
);
|
||||
}
|
||||
|
||||
var entriesAsync = GetEntriesAsync(stream);
|
||||
if (entriesAsync is null)
|
||||
{
|
||||
_entriesForCurrentReadStream = GetEntries(stream).GetEnumerator();
|
||||
return _entriesForCurrentReadStream.MoveNext();
|
||||
}
|
||||
|
||||
_asyncEntriesForCurrentReadStream = entriesAsync.GetAsyncEnumerator(cancellationToken);
|
||||
return await _asyncEntriesForCurrentReadStream.MoveNextAsync().ConfigureAwait(false);
|
||||
_entriesForCurrentReadStreamAsync = GetEntriesAsync(stream).GetAsyncEnumerator();
|
||||
return await _entriesForCurrentReadStreamAsync.MoveNextAsync();
|
||||
}
|
||||
|
||||
protected virtual Stream RequestInitialStream() =>
|
||||
@@ -200,16 +190,19 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
internal virtual bool NextEntryForCurrentStream() =>
|
||||
_entriesForCurrentReadStream.NotNull().MoveNext();
|
||||
|
||||
internal virtual ValueTask<bool> NextEntryForCurrentStreamAsync() =>
|
||||
_entriesForCurrentReadStreamAsync.NotNull().MoveNextAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Moves the current async enumerator to the next entry.
|
||||
/// </summary>
|
||||
internal virtual ValueTask<bool> NextEntryForCurrentStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
if (_asyncEntriesForCurrentReadStream is not null)
|
||||
if (_entriesForCurrentReadStreamAsync is not null)
|
||||
{
|
||||
return _asyncEntriesForCurrentReadStream.MoveNextAsync();
|
||||
return _entriesForCurrentReadStreamAsync.MoveNextAsync();
|
||||
}
|
||||
|
||||
return new ValueTask<bool>(NextEntryForCurrentStream());
|
||||
@@ -217,10 +210,14 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
|
||||
protected abstract IEnumerable<TEntry> GetEntries(Stream stream);
|
||||
|
||||
/// <summary>
|
||||
/// Optionally returns an async entry sequence for formats that support true async header parsing.
|
||||
/// </summary>
|
||||
protected virtual IAsyncEnumerable<TEntry>? GetEntriesAsync(Stream stream) => null;
|
||||
protected virtual async IAsyncEnumerable<TEntry> GetEntriesAsync(Stream stream)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
foreach (var entry in GetEntries(stream))
|
||||
{
|
||||
yield return entry;
|
||||
}
|
||||
}
|
||||
|
||||
#region Entry Skip/Write
|
||||
|
||||
@@ -441,4 +438,5 @@ public abstract class AbstractReader<TEntry, TVolume> : IReader
|
||||
#endregion
|
||||
|
||||
IEntry IReader.Entry => Entry;
|
||||
IEntry IReaderAsync.Entry => Entry;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,28 @@ public interface IReader : IDisposable
|
||||
/// <param name="writableStream"></param>
|
||||
void WriteEntryTo(Stream writableStream);
|
||||
|
||||
bool Cancelled { get; }
|
||||
void Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Moves to the next entry by reading more data from the underlying stream. This skips if data has not been read.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool MoveToNextEntry();
|
||||
|
||||
/// <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();
|
||||
}
|
||||
|
||||
public interface IReaderAsync : IAsyncDisposable
|
||||
{
|
||||
ArchiveType ArchiveType { get; }
|
||||
|
||||
IEntry Entry { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses the current entry to the stream asynchronously. This cannot be called twice for the current entry.
|
||||
/// </summary>
|
||||
@@ -28,12 +50,6 @@ public interface IReader : IDisposable
|
||||
bool Cancelled { get; }
|
||||
void Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Moves to the next entry by reading more data from the underlying stream. This skips if data has not been read.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
@@ -41,12 +57,6 @@ public interface IReader : IDisposable
|
||||
/// <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.
|
||||
|
||||
69
src/SharpCompress/Readers/IReaderAsyncExtensions.cs
Normal file
69
src/SharpCompress/Readers/IReaderAsyncExtensions.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Readers;
|
||||
|
||||
public static class IReaderAsyncExtensions
|
||||
{
|
||||
extension(IReaderAsync reader)
|
||||
{
|
||||
/// <summary>
|
||||
/// Extract to specific directory asynchronously, retaining filename
|
||||
/// </summary>
|
||||
public async Task WriteEntryToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await ExtractionMethods
|
||||
.WriteEntryToDirectoryAsync(
|
||||
reader.Entry,
|
||||
destinationDirectory,
|
||||
options,
|
||||
reader.WriteEntryToFileAsync,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific file asynchronously
|
||||
/// </summary>
|
||||
public async Task WriteEntryToFileAsync(
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await ExtractionMethods
|
||||
.WriteEntryToFileAsync(
|
||||
reader.Entry,
|
||||
destinationFileName,
|
||||
options,
|
||||
async (x, fm, ct) =>
|
||||
{
|
||||
using var fs = File.Open(destinationFileName, fm);
|
||||
await reader.WriteEntryToAsync(fs, ct).ConfigureAwait(false);
|
||||
},
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Extract all remaining unread entries to specific directory asynchronously, retaining filename
|
||||
/// </summary>
|
||||
public async Task WriteAllToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
while (await reader.MoveToNextEntryAsync(cancellationToken))
|
||||
{
|
||||
await reader
|
||||
.WriteEntryToDirectoryAsync(destinationDirectory, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Readers;
|
||||
@@ -66,62 +64,5 @@ public static class IReaderExtensions
|
||||
reader.WriteEntryTo(fs);
|
||||
}
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory asynchronously, retaining filename
|
||||
/// </summary>
|
||||
public async Task WriteEntryToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await ExtractionMethods
|
||||
.WriteEntryToDirectoryAsync(
|
||||
reader.Entry,
|
||||
destinationDirectory,
|
||||
options,
|
||||
reader.WriteEntryToFileAsync,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific file asynchronously
|
||||
/// </summary>
|
||||
public async Task WriteEntryToFileAsync(
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await ExtractionMethods
|
||||
.WriteEntryToFileAsync(
|
||||
reader.Entry,
|
||||
destinationFileName,
|
||||
options,
|
||||
async (x, fm, ct) =>
|
||||
{
|
||||
using var fs = File.Open(destinationFileName, fm);
|
||||
await reader.WriteEntryToAsync(fs, ct).ConfigureAwait(false);
|
||||
},
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Extract all remaining unread entries to specific directory asynchronously, retaining filename
|
||||
/// </summary>
|
||||
public async Task WriteAllToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
while (await reader.MoveToNextEntryAsync(cancellationToken))
|
||||
{
|
||||
await reader
|
||||
.WriteEntryToDirectoryAsync(destinationDirectory, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,9 @@ public interface IReaderFactory : Factories.IFactory
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
IReader OpenReader(Stream stream, ReaderOptions? options);
|
||||
|
||||
/// <summary>
|
||||
/// Opens a Reader asynchronously for Non-seeking usage
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
ValueTask<IReader> OpenReaderAsync(
|
||||
ValueTask<IReaderAsync> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
CancellationToken cancellationToken
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public static class ReaderFactory
|
||||
/// <param name="options"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<IReader> OpenAsync(
|
||||
public static ValueTask<IReaderAsync> OpenAsync(
|
||||
string filePath,
|
||||
ReaderOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -47,7 +47,7 @@ public static class ReaderFactory
|
||||
/// <param name="options"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<IReader> OpenAsync(
|
||||
public static ValueTask<IReaderAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -110,14 +110,7 @@ public static class ReaderFactory
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a Reader for Non-seeking usage asynchronously
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<IReader> OpenAsync(
|
||||
public static async ValueTask<IReaderAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -98,7 +98,7 @@ public class ZipReader : AbstractReader<ZipEntry, ZipVolume>
|
||||
/// <summary>
|
||||
/// Returns entries asynchronously for streams that only support async reads.
|
||||
/// </summary>
|
||||
protected override IAsyncEnumerable<ZipEntry>? GetEntriesAsync(Stream stream) =>
|
||||
protected override IAsyncEnumerable<ZipEntry> GetEntriesAsync(Stream stream) =>
|
||||
new ZipEntryAsyncEnumerable(_headerFactory, stream);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,6 +9,7 @@ using SharpCompress.Common;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using SharpCompress.Writers;
|
||||
using Xunit;
|
||||
|
||||
@@ -25,7 +26,7 @@ public class AsyncTests : TestBase
|
||||
#else
|
||||
await using var stream = File.OpenRead(testArchive);
|
||||
#endif
|
||||
using var reader = ReaderFactory.Open(stream);
|
||||
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
|
||||
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
@@ -50,9 +51,9 @@ public class AsyncTests : TestBase
|
||||
#else
|
||||
await using var stream = File.OpenRead(testArchive);
|
||||
#endif
|
||||
using var reader = ReaderFactory.Open(stream);
|
||||
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
|
||||
|
||||
while (reader.MoveToNextEntry())
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
@@ -118,7 +119,10 @@ public class AsyncTests : TestBase
|
||||
|
||||
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz");
|
||||
using var stream = File.OpenRead(testArchive);
|
||||
using var reader = ReaderFactory.Open(stream);
|
||||
await using var reader = await ReaderFactory.OpenAsync(
|
||||
new AsyncOnlyStream(stream),
|
||||
cancellationToken: cts.Token
|
||||
);
|
||||
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
|
||||
@@ -70,7 +70,7 @@ public class GZipReaderAsyncTests : ReaderTests
|
||||
bufferSize: options.BufferSize
|
||||
);
|
||||
using var testStream = new TestStream(protectedStream);
|
||||
using (var reader = ReaderFactory.Open(testStream, options))
|
||||
await using (var reader = await ReaderFactory.OpenAsync(testStream, options, default))
|
||||
{
|
||||
await UseReaderAsync(reader, expectedCompression);
|
||||
protectedStream.ThrowOnDispose = false;
|
||||
@@ -82,9 +82,9 @@ public class GZipReaderAsyncTests : ReaderTests
|
||||
Assert.True(options.LeaveStreamOpen != testStream.IsDisposed, message);
|
||||
}
|
||||
|
||||
private async Task UseReaderAsync(IReader reader, CompressionType expectedCompression)
|
||||
private async Task UseReaderAsync(IReaderAsync reader, CompressionType expectedCompression)
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,9 @@ using System.Threading.Tasks;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Zip;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.Tar;
|
||||
using SharpCompress.Writers.Zip;
|
||||
@@ -538,9 +540,14 @@ public class ProgressReportTests : TestBase
|
||||
archiveStream.Position = 0;
|
||||
var readerOptions = new ReaderOptions { Progress = progress };
|
||||
|
||||
using (var reader = ReaderFactory.Open(archiveStream, readerOptions))
|
||||
await using (
|
||||
var reader = await ReaderFactory.OpenAsync(
|
||||
new AsyncOnlyStream(archiveStream),
|
||||
readerOptions
|
||||
)
|
||||
)
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
|
||||
@@ -647,11 +647,11 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
using var stream = File.OpenRead(testArchive);
|
||||
using var archive = ArchiveFactory.Open(stream);
|
||||
Assert.True(archive.IsSolid);
|
||||
using (var reader = archive.ExtractAllEntries())
|
||||
await using var archive = await ArchiveFactory.OpenAsync(stream);
|
||||
Assert.True(await archive.IsSolidAsync());
|
||||
await using (var reader = await archive.ExtractAllEntriesAsync())
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
@@ -665,7 +665,7 @@ public class RarArchiveAsyncTests : ArchiveTests
|
||||
}
|
||||
VerifyFiles();
|
||||
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
await foreach (var entry in archive.EntriesAsync.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
|
||||
@@ -7,6 +7,7 @@ using SharpCompress.Archives.Rar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Rar;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Rar;
|
||||
@@ -204,7 +205,7 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
private async Task DoRar_Entry_Stream_Async(string filename)
|
||||
{
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
await using (var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream)))
|
||||
{
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
@@ -248,9 +249,14 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
using (
|
||||
var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar"))
|
||||
)
|
||||
using (var reader = ReaderFactory.Open(stream, new ReaderOptions { LookForHeader = true }))
|
||||
await using (
|
||||
var reader = await ReaderFactory.OpenAsync(
|
||||
new AsyncOnlyStream(stream),
|
||||
new ReaderOptions { LookForHeader = true }
|
||||
)
|
||||
)
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
await reader.WriteEntryToDirectoryAsync(
|
||||
@@ -310,8 +316,11 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
private async Task DoRar_Solid_Skip_Reader_Async(string filename)
|
||||
{
|
||||
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename));
|
||||
using var reader = ReaderFactory.Open(stream, new ReaderOptions { LookForHeader = true });
|
||||
while (reader.MoveToNextEntry())
|
||||
await using var reader = await ReaderFactory.OpenAsync(
|
||||
new AsyncOnlyStream(stream),
|
||||
new ReaderOptions { LookForHeader = true }
|
||||
);
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (reader.Entry.Key.NotNull().Contains("jpg"))
|
||||
{
|
||||
@@ -333,8 +342,11 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
private async Task DoRar_Reader_Skip_Async(string filename)
|
||||
{
|
||||
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename));
|
||||
using var reader = ReaderFactory.Open(stream, new ReaderOptions { LookForHeader = true });
|
||||
while (reader.MoveToNextEntry())
|
||||
await using var reader = await ReaderFactory.OpenAsync(
|
||||
new AsyncOnlyStream(stream),
|
||||
new ReaderOptions { LookForHeader = true }
|
||||
);
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (reader.Entry.Key.NotNull().Contains("jpg"))
|
||||
{
|
||||
@@ -355,7 +367,10 @@ public class RarReaderAsyncTests : ReaderTests
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
using Stream stream = File.OpenRead(testArchive);
|
||||
using var reader = ReaderFactory.Open(stream, readerOptions ?? new ReaderOptions());
|
||||
await using var reader = await ReaderFactory.OpenAsync(
|
||||
new AsyncOnlyStream(stream),
|
||||
readerOptions ?? new ReaderOptions()
|
||||
);
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
|
||||
@@ -145,7 +145,13 @@ public abstract class ReaderTests : TestBase
|
||||
bufferSize: options.BufferSize
|
||||
);
|
||||
using var testStream = new TestStream(protectedStream);
|
||||
using (var reader = ReaderFactory.Open(testStream, options))
|
||||
await using (
|
||||
var reader = await ReaderFactory.OpenAsync(
|
||||
new AsyncOnlyStream(testStream),
|
||||
options,
|
||||
cancellationToken
|
||||
)
|
||||
)
|
||||
{
|
||||
await UseReaderAsync(reader, expectedCompression, cancellationToken);
|
||||
protectedStream.ThrowOnDispose = false;
|
||||
@@ -158,7 +164,7 @@ public abstract class ReaderTests : TestBase
|
||||
}
|
||||
|
||||
public async Task UseReaderAsync(
|
||||
IReader reader,
|
||||
IReaderAsync reader,
|
||||
CompressionType? expectedCompression,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
|
||||
@@ -23,9 +23,9 @@ public class TarReaderAsyncTests : ReaderTests
|
||||
using Stream stream = new ForwardOnlyStream(
|
||||
File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"))
|
||||
);
|
||||
using var reader = ReaderFactory.Open(stream);
|
||||
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
|
||||
var x = 0;
|
||||
while (reader.MoveToNextEntry())
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
@@ -182,14 +182,16 @@ public class TarReaderAsyncTests : ReaderTests
|
||||
{
|
||||
var archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar");
|
||||
using Stream stream = File.OpenRead(archiveFullPath);
|
||||
using var reader = ReaderFactory.Open(stream);
|
||||
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
Assert.True(reader.MoveToNextEntry());
|
||||
Assert.True(reader.MoveToNextEntry());
|
||||
Assert.True(await reader.MoveToNextEntryAsync());
|
||||
Assert.True(await reader.MoveToNextEntryAsync());
|
||||
await reader.WriteEntryToAsync(memoryStream);
|
||||
stream.Close();
|
||||
Assert.Throws<IncompleteArchiveException>(() => reader.MoveToNextEntry());
|
||||
await Assert.ThrowsAsync<IncompleteArchiveException>(async () =>
|
||||
await reader.MoveToNextEntryAsync()
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -197,14 +199,16 @@ public class TarReaderAsyncTests : ReaderTests
|
||||
{
|
||||
var archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "TarCorrupted.tar");
|
||||
using Stream stream = File.OpenRead(archiveFullPath);
|
||||
using var reader = ReaderFactory.Open(stream);
|
||||
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
Assert.True(reader.MoveToNextEntry());
|
||||
Assert.True(reader.MoveToNextEntry());
|
||||
Assert.True(await reader.MoveToNextEntryAsync());
|
||||
Assert.True(await reader.MoveToNextEntryAsync());
|
||||
await reader.WriteEntryToAsync(memoryStream);
|
||||
stream.Close();
|
||||
Assert.Throws<IncompleteArchiveException>(() => reader.MoveToNextEntry());
|
||||
await Assert.ThrowsAsync<IncompleteArchiveException>(async () =>
|
||||
await reader.MoveToNextEntryAsync()
|
||||
);
|
||||
}
|
||||
|
||||
#if LINUX
|
||||
|
||||
@@ -92,9 +92,10 @@ public class WriterTests : TestBase
|
||||
|
||||
readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default;
|
||||
|
||||
using var reader = ReaderFactory.Open(
|
||||
SharpCompressStream.Create(stream, leaveOpen: true),
|
||||
readerOptions
|
||||
await using var reader = await ReaderFactory.OpenAsync(
|
||||
new AsyncOnlyStream(SharpCompressStream.Create(stream, leaveOpen: true)),
|
||||
readerOptions,
|
||||
cancellationToken
|
||||
);
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
|
||||
@@ -20,7 +20,7 @@ public class ZipReaderAsyncTests : ReaderTests
|
||||
{
|
||||
var path = Path.Combine(TEST_ARCHIVES_PATH, "PrePostHeaders.zip");
|
||||
using Stream stream = new ForwardOnlyStream(File.OpenRead(path));
|
||||
using var reader = ReaderFactory.Open(stream);
|
||||
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
|
||||
var count = 0;
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
@@ -65,7 +65,7 @@ public class ZipReaderAsyncTests : ReaderTests
|
||||
using Stream stream = new ForwardOnlyStream(
|
||||
File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip"))
|
||||
);
|
||||
using var reader = ReaderFactory.Open(stream);
|
||||
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
|
||||
var x = 0;
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
@@ -144,7 +144,7 @@ public class ZipReaderAsyncTests : ReaderTests
|
||||
using var stream = new TestStream(
|
||||
File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip"))
|
||||
);
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
await using (var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream)))
|
||||
{
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
@@ -168,7 +168,7 @@ public class ZipReaderAsyncTests : ReaderTests
|
||||
File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip"))
|
||||
)
|
||||
);
|
||||
var reader = await ReaderFactory.OpenAsync(stream);
|
||||
await using var reader = await ReaderFactory.OpenAsync(stream);
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
|
||||
Reference in New Issue
Block a user