diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs index 14a48dbd..56ea0d9f 100644 --- a/src/SharpCompress/Archives/IArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveExtensions.cs @@ -1,4 +1,9 @@ +using System; +using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using SharpCompress.Common; namespace SharpCompress.Archives; @@ -19,4 +24,54 @@ public static class IArchiveExtensions entry.WriteToDirectory(destinationDirectory, options); } } + + /// + /// Extracts the archive to the destination directory. Directories will be created as needed. + /// + /// The archive to extract. + /// The folder to extract into. + /// Optional progress report callback. + /// Optional cancellation token. + public static void ExtractToDirectory( + this IArchive archive, + string destination, + Action? progressReport = null, + CancellationToken cancellationToken = default + ) + { + // Prepare for progress reporting + var totalBytes = archive.TotalUncompressSize; + var bytesRead = 0L; + + // Tracking for created directories. + var seenDirectories = new HashSet(); + + // Extract + var entries = archive.ExtractAllEntries(); + while (entries.MoveToNextEntry()) + { + cancellationToken.ThrowIfCancellationRequested(); + + var entry = entries.Entry; + if (entry.IsDirectory) + { + continue; + } + + // Create each directory + var path = Path.Combine(destination, entry.Key); + if (Path.GetDirectoryName(path) is { } directory && seenDirectories.Add(path)) + { + Directory.CreateDirectory(directory); + } + + // Write file + using var fs = File.OpenWrite(path); + entries.WriteEntryTo(fs); + + // Update progress + bytesRead += entry.Size; + progressReport?.Invoke(bytesRead / (double)totalBytes); + } + } }