Files
sharpcompress/src/SharpCompress/Archives/IAsyncArchiveExtensions.cs
Adam Hathcock d6efe32cda fmt
2026-05-29 09:25:52 +01:00

127 lines
4.5 KiB
C#

using System;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Readers;
namespace SharpCompress.Archives;
public static class IAsyncArchiveExtensions
{
extension(IAsyncArchive archive)
{
/// <summary>
/// Extract to specific directory asynchronously with progress reporting and cancellation support
/// </summary>
/// <param name="destinationDirectory">The folder to extract into.</param>
/// <param name="options">Extraction options.</param>
/// <param name="progress">Optional progress reporter for tracking extraction progress.</param>
/// <param name="cancellationToken">Optional cancellation token.</param>
public async ValueTask WriteToDirectoryAsync(
string destinationDirectory,
ExtractionOptions? options = null,
IProgress<ProgressReport>? progress = null,
CancellationToken cancellationToken = default
)
{
if (
await archive.IsSolidAsync().ConfigureAwait(false)
|| archive.Type == ArchiveType.SevenZip
)
{
var totalBytes = await archive.TotalUncompressedSizeAsync().ConfigureAwait(false);
var bytesRead = 0L;
await using var reader = await archive
.ExtractAllEntriesAsync()
.ConfigureAwait(false);
while (await reader.MoveToNextEntryAsync(cancellationToken).ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
await reader
.WriteEntryToDirectoryAsync(
destinationDirectory,
options,
cancellationToken
)
.ConfigureAwait(false);
if (reader.Entry.IsDirectory)
{
continue;
}
bytesRead += reader.Entry.Size;
progress?.Report(
new ProgressReport(reader.Entry.Key ?? string.Empty, bytesRead, totalBytes)
);
}
}
else
{
await archive
.WriteToDirectoryAsyncInternal(
destinationDirectory,
options,
progress,
cancellationToken
)
.ConfigureAwait(false);
}
}
private async ValueTask WriteToDirectoryAsyncInternal(
string destinationDirectory,
ExtractionOptions? options,
IProgress<ProgressReport>? progress,
CancellationToken cancellationToken
)
{
options ??= new ExtractionOptions();
var fullDestinationDirectoryPath = DirectoryManagement.GetFullDestinationDirectoryPath(
destinationDirectory
);
var totalBytes = await archive.TotalUncompressedSizeAsync().ConfigureAwait(false);
var bytesRead = 0L;
await foreach (
var entry in archive
.EntriesAsync.WithCancellation(cancellationToken)
.ConfigureAwait(false)
)
{
cancellationToken.ThrowIfCancellationRequested();
if (entry.IsDirectory)
{
await entry
.WriteEntryToDirectoryAsyncCore(
fullDestinationDirectoryPath,
options,
null,
cancellationToken
)
.ConfigureAwait(false);
continue;
}
await entry
.WriteEntryToDirectoryAsyncCore(
fullDestinationDirectoryPath,
options,
async (path, ct) =>
await entry.WriteToFileAsync(path, options, ct).ConfigureAwait(false),
cancellationToken
)
.ConfigureAwait(false);
bytesRead += entry.Size;
progress?.Report(
new ProgressReport(entry.Key ?? string.Empty, bytesRead, totalBytes)
);
}
}
}
}