From c7c143fed975cb0618c2a675e086ed1b634da37a Mon Sep 17 00:00:00 2001 From: James Hood Date: Wed, 19 Jul 2023 08:22:15 -0400 Subject: [PATCH 1/3] Add `ExtractToDirectoryAsync` extension method on `IArchive` that is very fast compared to `WriteToDirectory`. --- .../Archives/IArchiveExtensions.cs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs index 14a48dbd..51e07693 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,56 @@ public static class IArchiveExtensions entry.WriteToDirectory(destinationDirectory, options); } } + + /// + /// Extracts the archive to the destination directory in the thread pool. Directories will be created as needed. + /// + /// The archive to extract. + /// The folder to extract into. + /// Optional progress report callback. + /// Optional cancellation token + public static Task ExtractToDirectoryAsync( + this IArchive archive, + string destination, + Action? progressReport = null, + CancellationToken cancellationToken = default + ) => Task.Run(() => + { + // 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); // TODO: Some day, this may be async. + + // Update progress + bytesRead += entry.Size; + progressReport?.Invoke(bytesRead / (double)totalBytes); + } + }, + cancellationToken); } From 4e23b84999ffbdcf48fb8e8487023ea9929962c9 Mon Sep 17 00:00:00 2001 From: James Hood Date: Fri, 21 Jul 2023 13:17:42 -0400 Subject: [PATCH 2/3] Remove Task aspect --- .../Archives/IArchiveExtensions.cs | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs index 51e07693..2a504b39 100644 --- a/src/SharpCompress/Archives/IArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveExtensions.cs @@ -26,54 +26,53 @@ public static class IArchiveExtensions } /// - /// Extracts the archive to the destination directory in the thread pool. Directories will be created as needed. + /// 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 Task ExtractToDirectoryAsync( + /// Optional cancellation token. + public static void ExtractToDirectory( this IArchive archive, string destination, Action? progressReport = null, CancellationToken cancellationToken = default - ) => Task.Run(() => - { - // Prepare for progress reporting - var totalBytes = archive.TotalUncompressSize; - var bytesRead = 0L; + ) + { + // Prepare for progress reporting + var totalBytes = archive.TotalUncompressSize; + var bytesRead = 0L; - // Tracking for created directories. - var seenDirectories = new HashSet(); + // Tracking for created directories. + var seenDirectories = new HashSet(); - // Extract - var entries = archive.ExtractAllEntries(); - while (entries.MoveToNextEntry()) - { - cancellationToken.ThrowIfCancellationRequested(); + // Extract + var entries = archive.ExtractAllEntries(); + while (entries.MoveToNextEntry()) + { + cancellationToken.ThrowIfCancellationRequested(); - var entry = entries.Entry; - if (entry.IsDirectory) - { - continue; - } + 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); - } + // 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); // TODO: Some day, this may be async. + // Write file + using var fs = File.OpenWrite(path); + entries.WriteEntryTo(fs); - // Update progress - bytesRead += entry.Size; - progressReport?.Invoke(bytesRead / (double)totalBytes); - } - }, - cancellationToken); + // Update progress + bytesRead += entry.Size; + progressReport?.Invoke(bytesRead / (double)totalBytes); + } + } } From ec01225225889c871c8a5d64596a2a3465e22f89 Mon Sep 17 00:00:00 2001 From: FlsZen Date: Sun, 13 Aug 2023 12:52:14 -0400 Subject: [PATCH 3/3] It looks like build format wants this on one line --- src/SharpCompress/Archives/IArchiveExtensions.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs index 2a504b39..56ea0d9f 100644 --- a/src/SharpCompress/Archives/IArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveExtensions.cs @@ -60,8 +60,7 @@ public static class IArchiveExtensions // Create each directory var path = Path.Combine(destination, entry.Key); - if (Path.GetDirectoryName(path) is { } directory - && seenDirectories.Add(path)) + if (Path.GetDirectoryName(path) is { } directory && seenDirectories.Add(path)) { Directory.CreateDirectory(directory); }