Fix async reader variable types - Remove double await on ReaderFactory.OpenAsync and use IAsyncReader

- Removed 'await' keyword before ReaderFactory.OpenAsync() calls since the method returns IAsyncReader directly (not Task)
- Changed ZipReader.Open() to ReaderFactory.OpenAsync() in Zip64AsyncTests.ReadForwardOnlyAsync()
- Changed TarReader.Open() to ReaderFactory.OpenAsync() in TarReaderAsyncTests.Tar_BZip2_Entry_Stream_Async()
- Fixed EntryStream disposal from 'await using' to 'using' since EntryStream doesn't implement IAsyncDisposable
- These changes fix compilation errors where async methods were being called on IReader (synchronous) instead of IAsyncReader (asynchronous)
This commit is contained in:
Adam Hathcock
2026-01-12 14:14:46 +00:00
parent 0615d17b8b
commit 38203fb950
14 changed files with 182 additions and 127 deletions

View File

@@ -32,10 +32,7 @@ public interface IArchiveFactory : IFactory
/// </summary>
/// <param name="stream">An open, readable and seekable stream.</param>
/// <param name="readerOptions">reading options.</param>
IAsyncArchive OpenAsync(
Stream stream,
ReaderOptions? readerOptions = null
);
IAsyncArchive OpenAsync(Stream stream, ReaderOptions? readerOptions = null);
/// <summary>
/// Constructor with a FileInfo object to an existing file.

View File

@@ -33,10 +33,7 @@ public interface IMultiArchiveFactory : IFactory
/// </summary>
/// <param name="streams"></param>
/// <param name="readerOptions">reading options.</param>
IAsyncArchive OpenAsync(
IReadOnlyList<Stream> streams,
ReaderOptions? readerOptions = null
);
IAsyncArchive OpenAsync(IReadOnlyList<Stream> streams, ReaderOptions? readerOptions = null);
/// <summary>
/// Constructor with IEnumerable Stream objects, multi and split support.

View File

@@ -39,7 +39,9 @@ public static class AsyncEnumerableExtensions
return list;
}
public static async IAsyncEnumerable<TResult> CastAsync<TResult>(this IAsyncEnumerable<object?> source)
public static async IAsyncEnumerable<TResult> CastAsync<TResult>(
this IAsyncEnumerable<object?> source
)
where TResult : class
{
await foreach (var item in source)
@@ -62,49 +64,74 @@ public static class AsyncEnumerableExtensions
return result;
}
extension<T>(IAsyncEnumerable<T> source)
public static async ValueTask<bool> AllAsync<T>(
this IAsyncEnumerable<T> source,
Func<T, bool> predicate
)
{
public async ValueTask<bool> AllAsync(Func<T, bool> predicate)
await foreach (var item in source)
{
await foreach (var item in source)
if (!predicate(item))
{
if (!predicate(item))
{
return false;
}
}
return true;
}
public async IAsyncEnumerable<T> WhereAsync(Func<T, bool> predicate)
{
await foreach (var item in source)
{
if (predicate(item))
{
yield return item;
}
return false;
}
}
public async ValueTask<T> FirstAsync()
{
await foreach (var item in source)
{
return item;
}
throw new InvalidOperationException("The source sequence is empty.");
}
return true;
}
public async ValueTask<T?> FirstOrDefaultAsync()
{
await foreach (var item in source)
{
return item;
}
public static IAsyncEnumerable<T> Where<T>(
this IAsyncEnumerable<T> source,
Func<T, bool> predicate
)
{
return WhereIterator(source, predicate);
}
return default;
private static async IAsyncEnumerable<T> WhereIterator<T>(
IAsyncEnumerable<T> source,
Func<T, bool> predicate
)
{
await foreach (var item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
public static async IAsyncEnumerable<T> WhereAsync<T>(
this IAsyncEnumerable<T> source,
Func<T, bool> predicate
)
{
await foreach (var item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
public static async ValueTask<T> FirstAsync<T>(this IAsyncEnumerable<T> source)
{
await foreach (var item in source)
{
return item;
}
throw new InvalidOperationException("The source sequence is empty.");
}
public static async ValueTask<T?> FirstOrDefaultAsync<T>(this IAsyncEnumerable<T> source)
{
await foreach (var item in source)
{
return item;
}
return default;
}
}

View File

@@ -26,7 +26,7 @@ public class AsyncTests : TestBase
#else
await using var stream = File.OpenRead(testArchive);
#endif
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await using var reader = ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await reader.WriteAllToDirectoryAsync(
SCRATCH_FILES_PATH,
@@ -51,7 +51,7 @@ public class AsyncTests : TestBase
#else
await using var stream = File.OpenRead(testArchive);
#endif
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await using var reader = ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
while (await reader.MoveToNextEntryAsync())
{
@@ -103,12 +103,8 @@ public class AsyncTests : TestBase
#else
await using (var stream = File.Create(outputPath))
#endif
await using (
var writer = await WriterFactory.OpenAsync(
stream,
ArchiveType.Zip,
CompressionType.Deflate
)
using (
var writer = WriterFactory.OpenAsync(stream, ArchiveType.Zip, CompressionType.Deflate)
)
{
var testFile = Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz");
@@ -123,7 +119,7 @@ public class AsyncTests : TestBase
// Verify the archive was created and contains the entry
Assert.True(File.Exists(outputPath));
await using var archive = await ZipArchive.OpenAsync(outputPath);
await using var archive = ZipArchive.OpenAsync(outputPath);
Assert.Single(await archive.EntriesAsync.WhereAsync(e => !e.IsDirectory).ToListAsync());
}
@@ -139,7 +135,7 @@ public class AsyncTests : TestBase
#else
await using var stream = File.OpenRead(testArchive);
#endif
await using var reader = await ReaderFactory.OpenAsync(
await using var reader = ReaderFactory.OpenAsync(
new AsyncOnlyStream(stream),
cancellationToken: cts.Token
);
@@ -193,7 +189,7 @@ public class AsyncTests : TestBase
#else
await using var stream = File.OpenRead(testArchive);
#endif
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await using var reader = ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
while (await reader.MoveToNextEntryAsync())
{

View File

@@ -47,17 +47,24 @@ public class GZipArchiveAsyncTests : ArchiveTests
#else
await using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
#endif
await using (var archive = await GZipArchive.OpenAsync(stream))
{
var entry = await archive.EntriesAsync.FirstAsync();
await entry.WriteToFileAsync(Path.Combine(SCRATCH_FILES_PATH, entry.Key.NotNull()));
IAsyncArchive archive = await GZipArchive.OpenAsync(stream);
try
{
var entry = await archive.EntriesAsync.FirstAsync();
await entry.WriteToFileAsync(Path.Combine(SCRATCH_FILES_PATH, entry.Key.NotNull()));
var size = entry.Size;
var scratch = new FileInfo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"));
var test = new FileInfo(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
var size = entry.Size;
var scratch = new FileInfo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"));
var test = new FileInfo(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
Assert.Equal(size, scratch.Length);
Assert.Equal(size, test.Length);
Assert.Equal(size, scratch.Length);
Assert.Equal(size, test.Length);
}
finally
{
archive.DisposeAsync().AsTask().Wait();
}
}
CompareArchivesByPath(
Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"),
@@ -74,11 +81,18 @@ public class GZipArchiveAsyncTests : ArchiveTests
#else
await using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
#endif
await using var archive = await GZipArchive.OpenAsync(stream);
await Assert.ThrowsAsync<InvalidFormatException>(() =>
archive.AddEntry("jpg\\test.jpg", jpg)
);
await archive.SaveToAsync(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"));
IAsyncArchive archive = await GZipArchive.OpenAsync(stream);
try
{
await Assert.ThrowsAsync<InvalidFormatException>(() =>
archive.AddEntry("jpg\\test.jpg", jpg)
);
await archive.SaveToAsync(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"));
}
finally
{
await archive.DisposeAsync();
}
}
[Fact]
@@ -95,7 +109,7 @@ public class GZipArchiveAsyncTests : ArchiveTests
inputStream.Position = 0;
}
await using var archive = GZipArchive.Open(inputStream);
using var archive = GZipArchive.Open(inputStream);
var archiveEntry = archive.Entries.First();
MemoryStream tarStream;

View File

@@ -22,7 +22,7 @@ public class GZipReaderAsyncTests : ReaderTests
{
//read only as GZip item
using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await using var reader = ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
while (await reader.MoveToNextEntryAsync())
{
Assert.NotEqual(0, reader.Entry.Size);
@@ -70,7 +70,7 @@ public class GZipReaderAsyncTests : ReaderTests
bufferSize: options.BufferSize
);
using var testStream = new TestStream(protectedStream);
await using (var reader = await ReaderFactory.OpenAsync(testStream, options, default))
await using (var reader = ReaderFactory.OpenAsync(testStream, options, default))
{
await UseReaderAsync(reader, expectedCompression);
protectedStream.ThrowOnDispose = false;

View File

@@ -541,10 +541,7 @@ public class ProgressReportTests : TestBase
var readerOptions = new ReaderOptions { Progress = progress };
await using (
var reader = await ReaderFactory.OpenAsync(
new AsyncOnlyStream(archiveStream),
readerOptions
)
var reader = ReaderFactory.OpenAsync(new AsyncOnlyStream(archiveStream), readerOptions)
)
{
while (await reader.MoveToNextEntryAsync())

View File

@@ -205,7 +205,7 @@ public class RarReaderAsyncTests : ReaderTests
private async ValueTask DoRar_Entry_Stream_Async(string filename)
{
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
await using (var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream)))
await using (var reader = ReaderFactory.OpenAsync(new AsyncOnlyStream(stream)))
{
while (await reader.MoveToNextEntryAsync())
{
@@ -250,7 +250,7 @@ public class RarReaderAsyncTests : ReaderTests
var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar"))
)
await using (
var reader = await ReaderFactory.OpenAsync(
var reader = ReaderFactory.OpenAsync(
new AsyncOnlyStream(stream),
new ReaderOptions { LookForHeader = true }
)
@@ -316,7 +316,7 @@ public class RarReaderAsyncTests : ReaderTests
private async ValueTask DoRar_Solid_Skip_Reader_Async(string filename)
{
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename));
await using var reader = await ReaderFactory.OpenAsync(
await using var reader = ReaderFactory.OpenAsync(
new AsyncOnlyStream(stream),
new ReaderOptions { LookForHeader = true }
);
@@ -342,7 +342,7 @@ public class RarReaderAsyncTests : ReaderTests
private async ValueTask DoRar_Reader_Skip_Async(string filename)
{
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename));
await using var reader = await ReaderFactory.OpenAsync(
await using var reader = ReaderFactory.OpenAsync(
new AsyncOnlyStream(stream),
new ReaderOptions { LookForHeader = true }
);
@@ -367,7 +367,7 @@ public class RarReaderAsyncTests : ReaderTests
{
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
using Stream stream = File.OpenRead(testArchive);
await using var reader = await ReaderFactory.OpenAsync(
await using var reader = ReaderFactory.OpenAsync(
new AsyncOnlyStream(stream),
readerOptions ?? new ReaderOptions()
);

View File

@@ -146,7 +146,7 @@ public abstract class ReaderTests : TestBase
);
using var testStream = new TestStream(protectedStream);
await using (
var reader = await ReaderFactory.OpenAsync(
var reader = ReaderFactory.OpenAsync(
new AsyncOnlyStream(testStream),
options,
cancellationToken

View File

@@ -23,7 +23,7 @@ public class TarReaderAsyncTests : ReaderTests
using Stream stream = new ForwardOnlyStream(
File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"))
);
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await using var reader = ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
var x = 0;
while (await reader.MoveToNextEntryAsync())
{
@@ -73,7 +73,7 @@ public class TarReaderAsyncTests : ReaderTests
public async ValueTask Tar_BZip2_Entry_Stream_Async()
{
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2")))
using (var reader = TarReader.Open(stream))
await using (var reader = ReaderFactory.OpenAsync(stream))
{
while (await reader.MoveToNextEntryAsync())
{
@@ -184,7 +184,7 @@ public class TarReaderAsyncTests : ReaderTests
{
var archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar");
using Stream stream = File.OpenRead(archiveFullPath);
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await using var reader = ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
var memoryStream = new MemoryStream();
Assert.True(await reader.MoveToNextEntryAsync());
@@ -201,7 +201,7 @@ public class TarReaderAsyncTests : ReaderTests
{
var archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "TarCorrupted.tar");
using Stream stream = File.OpenRead(archiveFullPath);
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await using var reader = ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
var memoryStream = new MemoryStream();
Assert.True(await reader.MoveToNextEntryAsync());
@@ -220,7 +220,7 @@ public class TarReaderAsyncTests : ReaderTests
using Stream stream = File.OpenRead(
Path.Combine(TEST_ARCHIVES_PATH, "TarWithSymlink.tar.gz")
);
await using var reader = await ReaderFactory.OpenAsync(
await using var reader = ReaderFactory.OpenAsync(
new AsyncOnlyStream(stream),
new ReaderOptions { LookForHeader = true }
);

View File

@@ -92,7 +92,7 @@ public class WriterTests : TestBase
readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default;
await using var reader = await ReaderFactory.OpenAsync(
await using var reader = ReaderFactory.OpenAsync(
new AsyncOnlyStream(SharpCompressStream.Create(stream, leaveOpen: true)),
readerOptions,
cancellationToken

View File

@@ -198,28 +198,31 @@ public class Zip64AsyncTests : WriterTests
long size = 0;
ZipEntry? prev = null;
using (var fs = File.OpenRead(filename))
using (var rd = ZipReader.Open(fs, new ReaderOptions { LookForHeader = false }))
{
while (await rd.MoveToNextEntryAsync())
var rd = ReaderFactory.OpenAsync(fs, new ReaderOptions { LookForHeader = false });
await using (rd)
{
while (await rd.MoveToNextEntryAsync())
{
#if NETFRAMEWORK || NETSTANDARD2_0
using (var entryStream = await rd.OpenEntryStreamAsync())
{
await entryStream.SkipEntryAsync();
}
using (var entryStream = await rd.OpenEntryStreamAsync())
{
await entryStream.SkipEntryAsync();
}
#else
await using (var entryStream = await rd.OpenEntryStreamAsync())
{
await entryStream.SkipEntryAsync();
}
await using (var entryStream = await rd.OpenEntryStreamAsync())
{
await entryStream.SkipEntryAsync();
}
#endif
count++;
if (prev != null)
{
size += prev.Size;
}
count++;
if (prev != null)
{
size += prev.Size;
}
prev = rd.Entry;
prev = (ZipEntry)rd.Entry;
}
}
}

View File

@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress;
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
using SharpCompress.Common;
@@ -125,8 +126,9 @@ public class ZipArchiveAsyncTests : ArchiveTests
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
var modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip");
using (var archive = ZipArchive.Open(unmodified))
using (IArchive baseArchive = ZipArchive.Open(unmodified))
{
IWritableArchive archive = (IWritableArchive)baseArchive;
var entry = archive.Entries.Single(x =>
x.Key.NotNull().EndsWith("jpg", StringComparison.OrdinalIgnoreCase)
);
@@ -148,8 +150,9 @@ public class ZipArchiveAsyncTests : ArchiveTests
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip");
var modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
using (var archive = ZipArchive.Open(unmodified))
using (IArchive baseArchive = ZipArchive.Open(unmodified))
{
IWritableArchive archive = (IWritableArchive)baseArchive;
archive.AddEntry("jpg\\test.jpg", jpg);
WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate);
@@ -166,7 +169,7 @@ public class ZipArchiveAsyncTests : ArchiveTests
var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
using (var archive = ZipArchive.Create())
using (ZipArchive archive = ZipArchive.Create())
{
archive.DeflateCompressionLevel = CompressionLevel.BestSpeed;
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
@@ -183,14 +186,21 @@ public class ZipArchiveAsyncTests : ArchiveTests
public async ValueTask Zip_Deflate_Entry_Stream_Async()
{
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip")))
await using (var archive = await ZipArchive.OpenAsync(new AsyncOnlyStream(stream)))
{
await foreach (var entry in archive.EntriesAsync.Where(entry => !entry.IsDirectory))
IAsyncArchive archive = ZipArchive.OpenAsync(new AsyncOnlyStream(stream));
try
{
await entry.WriteToDirectoryAsync(
SCRATCH_FILES_PATH,
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
);
await foreach (var entry in archive.EntriesAsync.Where(entry => !entry.IsDirectory))
{
await entry.WriteToDirectoryAsync(
SCRATCH_FILES_PATH,
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
);
}
}
finally
{
await archive.DisposeAsync();
}
}
VerifyFiles();
@@ -200,12 +210,19 @@ public class ZipArchiveAsyncTests : ArchiveTests
public async ValueTask Zip_Deflate_Archive_WriteToDirectoryAsync()
{
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip")))
await using (var archive = await ZipArchive.OpenAsync(new AsyncOnlyStream(stream)))
{
await archive.WriteToDirectoryAsync(
SCRATCH_FILES_PATH,
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
);
IAsyncArchive archive = ZipArchive.OpenAsync(new AsyncOnlyStream(stream));
try
{
await archive.WriteToDirectoryAsync(
SCRATCH_FILES_PATH,
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
);
}
finally
{
await archive.DisposeAsync();
}
}
VerifyFiles();
}
@@ -217,13 +234,20 @@ public class ZipArchiveAsyncTests : ArchiveTests
var progress = new Progress<ProgressReport>(report => progressReports.Add(report));
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip")))
await using (var archive = await ZipArchive.OpenAsync(new AsyncOnlyStream(stream)))
{
await archive.WriteToDirectoryAsync(
SCRATCH_FILES_PATH,
new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
progress
);
IAsyncArchive archive = ZipArchive.OpenAsync(new AsyncOnlyStream(stream));
try
{
await archive.WriteToDirectoryAsync(
SCRATCH_FILES_PATH,
new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
progress
);
}
finally
{
await archive.DisposeAsync();
}
}
VerifyFiles();

View File

@@ -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));
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await using var reader = 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"))
);
await using var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream));
await using var reader = 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"))
);
await using (var reader = await ReaderFactory.OpenAsync(new AsyncOnlyStream(stream)))
await using (var reader = 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"))
)
);
await using var reader = await ReaderFactory.OpenAsync(stream);
await using var reader = ReaderFactory.OpenAsync(stream);
while (await reader.MoveToNextEntryAsync())
{
if (!reader.Entry.IsDirectory)