From 3f9986c13c973f5e9b8e08da8bfb5e8259044a44 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Dec 2025 11:47:53 +0000
Subject: [PATCH 1/8] Initial plan
From 8b95e0a76d6b387533175730e2895ccd16772d07 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Dec 2025 11:57:01 +0000
Subject: [PATCH 2/8] Standardize on WriteToDirectory naming and add async
support
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
---
.../Archives/IArchiveExtensions.cs | 98 +++++++++++++++----
tests/SharpCompress.Test/ArchiveTests.cs | 2 +-
2 files changed, 82 insertions(+), 18 deletions(-)
diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs
index d9701da30..628155995 100644
--- a/src/SharpCompress/Archives/IArchiveExtensions.cs
+++ b/src/SharpCompress/Archives/IArchiveExtensions.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Readers;
@@ -19,21 +20,38 @@ public static void WriteToDirectory(
ExtractionOptions? options = null
)
{
- using var reader = archive.ExtractAllEntries();
- reader.WriteAllToDirectory(destinationDirectory, options);
+ // For solid archives (Rar, 7Zip), use the optimized reader-based approach
+ if (archive.IsSolid || archive.Type == ArchiveType.SevenZip)
+ {
+ using var reader = archive.ExtractAllEntries();
+ reader.WriteAllToDirectory(destinationDirectory, options);
+ }
+ else
+ {
+ // For non-solid archives, extract entries directly
+ foreach (var entry in archive.Entries)
+ {
+ if (!entry.IsDirectory)
+ {
+ entry.WriteToDirectory(destinationDirectory, options);
+ }
+ }
+ }
}
///
- /// Extracts the archive to the destination directory. Directories will be created as needed.
+ /// Extract to specific directory with progress reporting and cancellation support
///
/// The archive to extract.
- /// The folder to extract into.
+ /// The folder to extract into.
+ /// Extraction options.
/// Optional progress report callback.
/// Optional cancellation token.
- public static void ExtractToDirectory(
+ public static void WriteToDirectory(
this IArchive archive,
- string destination,
- Action? progressReport = null,
+ string destinationDirectory,
+ ExtractionOptions? options,
+ Action? progressReport,
CancellationToken cancellationToken = default
)
{
@@ -51,7 +69,10 @@ public static void ExtractToDirectory(
if (entry.IsDirectory)
{
- var dirPath = Path.Combine(destination, entry.Key.NotNull("Entry Key is null"));
+ var dirPath = Path.Combine(
+ destinationDirectory,
+ entry.Key.NotNull("Entry Key is null")
+ );
if (
Path.GetDirectoryName(dirPath + "/") is { } emptyDirectory
&& seenDirectories.Add(dirPath)
@@ -62,20 +83,63 @@ public static void ExtractToDirectory(
continue;
}
- // Create each directory if not already created
- var path = Path.Combine(destination, entry.Key.NotNull("Entry Key is null"));
- if (Path.GetDirectoryName(path) is { } directory)
+ // Use the entry's WriteToDirectory method which respects ExtractionOptions
+ entry.WriteToDirectory(destinationDirectory, options);
+
+ // Update progress
+ bytesRead += entry.Size;
+ progressReport?.Invoke(bytesRead / (double)totalBytes);
+ }
+ }
+
+ ///
+ /// Extract to specific directory asynchronously with progress reporting and cancellation support
+ ///
+ /// The archive to extract.
+ /// The folder to extract into.
+ /// Extraction options.
+ /// Optional progress report callback.
+ /// Optional cancellation token.
+ public static async Task WriteToDirectoryAsync(
+ this IArchive archive,
+ string destinationDirectory,
+ ExtractionOptions? options = null,
+ 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
+ foreach (var entry in archive.Entries)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (entry.IsDirectory)
{
- if (!Directory.Exists(directory) && !seenDirectories.Contains(directory))
+ var dirPath = Path.Combine(
+ destinationDirectory,
+ entry.Key.NotNull("Entry Key is null")
+ );
+ if (
+ Path.GetDirectoryName(dirPath + "/") is { } emptyDirectory
+ && seenDirectories.Add(dirPath)
+ )
{
- Directory.CreateDirectory(directory);
- seenDirectories.Add(directory);
+ Directory.CreateDirectory(emptyDirectory);
}
+ continue;
}
- // Write file
- using var fs = File.OpenWrite(path);
- entry.WriteTo(fs);
+ // Use the entry's WriteToDirectoryAsync method which respects ExtractionOptions
+ await entry
+ .WriteToDirectoryAsync(destinationDirectory, options, cancellationToken)
+ .ConfigureAwait(false);
// Update progress
bytesRead += entry.Size;
diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs
index 2f47e1215..916c9e2c0 100644
--- a/tests/SharpCompress.Test/ArchiveTests.cs
+++ b/tests/SharpCompress.Test/ArchiveTests.cs
@@ -261,7 +261,7 @@ protected void ArchiveExtractToDirectory(
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
using (var archive = ArchiveFactory.Open(new FileInfo(testArchive), readerOptions))
{
- archive.ExtractToDirectory(SCRATCH_FILES_PATH);
+ archive.WriteToDirectory(SCRATCH_FILES_PATH);
}
VerifyFiles();
}
From 0e59bf39f4bb77859416bad08c84bf8ff351b962 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Dec 2025 12:04:47 +0000
Subject: [PATCH 3/8] Add test for IArchive.WriteToDirectoryAsync
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
---
.../SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs
index 01fe9ca83..d964ddc71 100644
--- a/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs
+++ b/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs
@@ -194,4 +194,18 @@ await entry.WriteToDirectoryAsync(
}
VerifyFiles();
}
+
+ [Fact]
+ public async Task Zip_Deflate_Archive_WriteToDirectoryAsync()
+ {
+ using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip")))
+ using (var archive = ZipArchive.Open(stream))
+ {
+ await archive.WriteToDirectoryAsync(
+ SCRATCH_FILES_PATH,
+ new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
+ );
+ }
+ VerifyFiles();
+ }
}
From 54b64a8c3b7956f745bea7b14eb76dd0b9934430 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Dec 2025 12:06:36 +0000
Subject: [PATCH 4/8] Fix misleading variable name: emptyDirectory ->
parentDirectory
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
---
src/SharpCompress/Archives/IArchiveExtensions.cs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs
index 628155995..23af9ecb8 100644
--- a/src/SharpCompress/Archives/IArchiveExtensions.cs
+++ b/src/SharpCompress/Archives/IArchiveExtensions.cs
@@ -74,11 +74,11 @@ public static void WriteToDirectory(
entry.Key.NotNull("Entry Key is null")
);
if (
- Path.GetDirectoryName(dirPath + "/") is { } emptyDirectory
+ Path.GetDirectoryName(dirPath + "/") is { } parentDirectory
&& seenDirectories.Add(dirPath)
)
{
- Directory.CreateDirectory(emptyDirectory);
+ Directory.CreateDirectory(parentDirectory);
}
continue;
}
@@ -127,11 +127,11 @@ public static async Task WriteToDirectoryAsync(
entry.Key.NotNull("Entry Key is null")
);
if (
- Path.GetDirectoryName(dirPath + "/") is { } emptyDirectory
+ Path.GetDirectoryName(dirPath + "/") is { } parentDirectory
&& seenDirectories.Add(dirPath)
)
{
- Directory.CreateDirectory(emptyDirectory);
+ Directory.CreateDirectory(parentDirectory);
}
continue;
}
From 2f0eb0bd4b733929397c68881ae21904ff42a0d6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Dec 2025 13:25:36 +0000
Subject: [PATCH 5/8] Replace Action with IProgress for
progress reporting
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
---
.../Archives/IArchiveExtensions.cs | 24 ++++++++++++++-----
.../Zip/ZipArchiveAsyncTests.cs | 20 ++++++++++++++++
2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs
index 23af9ecb8..a0ac9d19c 100644
--- a/src/SharpCompress/Archives/IArchiveExtensions.cs
+++ b/src/SharpCompress/Archives/IArchiveExtensions.cs
@@ -45,13 +45,13 @@ public static void WriteToDirectory(
/// The archive to extract.
/// The folder to extract into.
/// Extraction options.
- /// Optional progress report callback.
+ /// Optional progress reporter for tracking extraction progress.
/// Optional cancellation token.
public static void WriteToDirectory(
this IArchive archive,
string destinationDirectory,
ExtractionOptions? options,
- Action? progressReport,
+ IProgress? progress,
CancellationToken cancellationToken = default
)
{
@@ -88,7 +88,13 @@ public static void WriteToDirectory(
// Update progress
bytesRead += entry.Size;
- progressReport?.Invoke(bytesRead / (double)totalBytes);
+ progress?.Report(
+ new ProgressReport(
+ entry.Key ?? string.Empty,
+ bytesRead,
+ totalBytes
+ )
+ );
}
}
@@ -98,13 +104,13 @@ public static void WriteToDirectory(
/// The archive to extract.
/// The folder to extract into.
/// Extraction options.
- /// Optional progress report callback.
+ /// Optional progress reporter for tracking extraction progress.
/// Optional cancellation token.
public static async Task WriteToDirectoryAsync(
this IArchive archive,
string destinationDirectory,
ExtractionOptions? options = null,
- Action? progressReport = null,
+ IProgress? progress = null,
CancellationToken cancellationToken = default
)
{
@@ -143,7 +149,13 @@ await entry
// Update progress
bytesRead += entry.Size;
- progressReport?.Invoke(bytesRead / (double)totalBytes);
+ progress?.Report(
+ new ProgressReport(
+ entry.Key ?? string.Empty,
+ bytesRead,
+ totalBytes
+ )
+ );
}
}
}
diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs
index d964ddc71..cd93a3c18 100644
--- a/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs
+++ b/tests/SharpCompress.Test/Zip/ZipArchiveAsyncTests.cs
@@ -208,4 +208,24 @@ await archive.WriteToDirectoryAsync(
}
VerifyFiles();
}
+
+ [Fact]
+ public async Task Zip_Deflate_Archive_WriteToDirectoryAsync_WithProgress()
+ {
+ var progressReports = new System.Collections.Generic.List();
+ var progress = new Progress(report => progressReports.Add(report));
+
+ using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip")))
+ using (var archive = ZipArchive.Open(stream))
+ {
+ await archive.WriteToDirectoryAsync(
+ SCRATCH_FILES_PATH,
+ new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
+ progress
+ );
+ }
+
+ VerifyFiles();
+ Assert.True(progressReports.Count > 0, "Progress reports should be generated");
+ }
}
From c701bbbee3697693bfcf76f81b543df19c14c848 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Dec 2025 13:31:35 +0000
Subject: [PATCH 6/8] Run CSharpier formatting and document check-format
process
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
---
AGENTS.md | 30 ++++++++++++++++---
.../Archives/IArchiveExtensions.cs | 16 ++--------
2 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
index c7b4a5a63..ae36265aa 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -32,12 +32,34 @@ SharpCompress is a pure C# compression library supporting multiple archive forma
- Use CSharpier for code formatting to ensure consistent style across the project
- CSharpier is configured as a local tool in `.config/dotnet-tools.json`
-- **To format code, run the task: `format` task (which runs `dotnet csharpier .` from project root)**
-- Restore tools with: `dotnet tool restore`
-- Format files from the project root with: `dotnet csharpier .`
-- Configure your IDE to format on save using CSharpier for the best experience
+
+### Commands
+
+1. **Restore tools** (first time only):
+ ```bash
+ dotnet tool restore
+ ```
+
+2. **Check if files are formatted correctly** (doesn't modify files):
+ ```bash
+ dotnet csharpier check .
+ ```
+ - Exit code 0: All files are properly formatted
+ - Exit code 1: Some files need formatting (will show which files and differences)
+
+3. **Format files** (modifies files):
+ ```bash
+ dotnet csharpier format .
+ ```
+ - Formats all files in the project to match CSharpier style
+ - Run from project root directory
+
+4. **Configure your IDE** to format on save using CSharpier for the best experience
+
+### Additional Notes
- The project also uses `.editorconfig` for editor settings (indentation, encoding, etc.)
- Let CSharpier handle code style while `.editorconfig` handles editor behavior
+- Always run `dotnet csharpier check .` before committing to verify formatting
## Project Setup and Structure
diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs
index a0ac9d19c..4ab4129bf 100644
--- a/src/SharpCompress/Archives/IArchiveExtensions.cs
+++ b/src/SharpCompress/Archives/IArchiveExtensions.cs
@@ -88,13 +88,7 @@ public static void WriteToDirectory(
// Update progress
bytesRead += entry.Size;
- progress?.Report(
- new ProgressReport(
- entry.Key ?? string.Empty,
- bytesRead,
- totalBytes
- )
- );
+ progress?.Report(new ProgressReport(entry.Key ?? string.Empty, bytesRead, totalBytes));
}
}
@@ -149,13 +143,7 @@ await entry
// Update progress
bytesRead += entry.Size;
- progress?.Report(
- new ProgressReport(
- entry.Key ?? string.Empty,
- bytesRead,
- totalBytes
- )
- );
+ progress?.Report(new ProgressReport(entry.Key ?? string.Empty, bytesRead, totalBytes));
}
}
}
From d39299176476a3fd230bb4b9ed1dc51e95e2be7d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Dec 2025 13:40:22 +0000
Subject: [PATCH 7/8] Remove CancellationToken from synchronous
WriteToDirectory overload
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
---
src/SharpCompress/Archives/IArchiveExtensions.cs | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs
index 4ab4129bf..00aae4686 100644
--- a/src/SharpCompress/Archives/IArchiveExtensions.cs
+++ b/src/SharpCompress/Archives/IArchiveExtensions.cs
@@ -40,19 +40,17 @@ public static void WriteToDirectory(
}
///
- /// Extract to specific directory with progress reporting and cancellation support
+ /// Extract to specific directory with progress reporting
///
/// The archive to extract.
/// The folder to extract into.
/// Extraction options.
/// Optional progress reporter for tracking extraction progress.
- /// Optional cancellation token.
public static void WriteToDirectory(
this IArchive archive,
string destinationDirectory,
ExtractionOptions? options,
- IProgress? progress,
- CancellationToken cancellationToken = default
+ IProgress? progress
)
{
// Prepare for progress reporting
@@ -65,8 +63,6 @@ public static void WriteToDirectory(
// Extract
foreach (var entry in archive.Entries)
{
- cancellationToken.ThrowIfCancellationRequested();
-
if (entry.IsDirectory)
{
var dirPath = Path.Combine(
From c2e01798f8bbe63fd4c3568d8e2d594d7c504ae9 Mon Sep 17 00:00:00 2001
From: Adam Hathcock
Date: Fri, 19 Dec 2025 14:09:01 +0000
Subject: [PATCH 8/8] refactor archive extensions
---
.../Archives/IArchiveExtensions.cs | 233 ++++++++++--------
1 file changed, 128 insertions(+), 105 deletions(-)
diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs
index 00aae4686..0d39c6e2c 100644
--- a/src/SharpCompress/Archives/IArchiveExtensions.cs
+++ b/src/SharpCompress/Archives/IArchiveExtensions.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
@@ -11,135 +10,159 @@ namespace SharpCompress.Archives;
public static class IArchiveExtensions
{
- ///
- /// Extract to specific directory, retaining filename
- ///
- public static void WriteToDirectory(
- this IArchive archive,
- string destinationDirectory,
- ExtractionOptions? options = null
- )
+ /// The archive to extract.
+ extension(IArchive archive)
{
- // For solid archives (Rar, 7Zip), use the optimized reader-based approach
- if (archive.IsSolid || archive.Type == ArchiveType.SevenZip)
+ ///
+ /// Extract to specific directory with progress reporting
+ ///
+ /// The folder to extract into.
+ /// Extraction options.
+ /// Optional progress reporter for tracking extraction progress.
+ public void WriteToDirectory(
+ string destinationDirectory,
+ ExtractionOptions? options = null,
+ IProgress? progress = null
+ )
{
- using var reader = archive.ExtractAllEntries();
- reader.WriteAllToDirectory(destinationDirectory, options);
+ // For solid archives (Rar, 7Zip), use the optimized reader-based approach
+ if (archive.IsSolid || archive.Type == ArchiveType.SevenZip)
+ {
+ using var reader = archive.ExtractAllEntries();
+ reader.WriteAllToDirectory(destinationDirectory, options);
+ }
+ else
+ {
+ // For non-solid archives, extract entries directly
+ archive.WriteToDirectoryInternal(destinationDirectory, options, progress);
+ }
}
- else
+
+ private void WriteToDirectoryInternal(
+ string destinationDirectory,
+ ExtractionOptions? options,
+ IProgress? progress
+ )
{
- // For non-solid archives, extract entries directly
+ // Prepare for progress reporting
+ var totalBytes = archive.TotalUncompressSize;
+ var bytesRead = 0L;
+
+ // Tracking for created directories.
+ var seenDirectories = new HashSet();
+
+ // Extract
foreach (var entry in archive.Entries)
{
- if (!entry.IsDirectory)
+ if (entry.IsDirectory)
{
- entry.WriteToDirectory(destinationDirectory, options);
+ var dirPath = Path.Combine(
+ destinationDirectory,
+ entry.Key.NotNull("Entry Key is null")
+ );
+ if (
+ Path.GetDirectoryName(dirPath + "/") is { } parentDirectory
+ && seenDirectories.Add(dirPath)
+ )
+ {
+ Directory.CreateDirectory(parentDirectory);
+ }
+ continue;
}
- }
- }
- }
- ///
- /// Extract to specific directory with progress reporting
- ///
- /// The archive to extract.
- /// The folder to extract into.
- /// Extraction options.
- /// Optional progress reporter for tracking extraction progress.
- public static void WriteToDirectory(
- this IArchive archive,
- string destinationDirectory,
- ExtractionOptions? options,
- IProgress? progress
- )
- {
- // Prepare for progress reporting
- var totalBytes = archive.TotalUncompressSize;
- var bytesRead = 0L;
+ // Use the entry's WriteToDirectory method which respects ExtractionOptions
+ entry.WriteToDirectory(destinationDirectory, options);
- // Tracking for created directories.
- var seenDirectories = new HashSet();
+ // Update progress
+ bytesRead += entry.Size;
+ progress?.Report(
+ new ProgressReport(entry.Key ?? string.Empty, bytesRead, totalBytes)
+ );
+ }
+ }
- // Extract
- foreach (var entry in archive.Entries)
+ ///
+ /// Extract to specific directory asynchronously with progress reporting and cancellation support
+ ///
+ /// The folder to extract into.
+ /// Extraction options.
+ /// Optional progress reporter for tracking extraction progress.
+ /// Optional cancellation token.
+ public async Task WriteToDirectoryAsync(
+ string destinationDirectory,
+ ExtractionOptions? options = null,
+ IProgress? progress = null,
+ CancellationToken cancellationToken = default
+ )
{
- if (entry.IsDirectory)
+ // For solid archives (Rar, 7Zip), use the optimized reader-based approach
+ if (archive.IsSolid || archive.Type == ArchiveType.SevenZip)
{
- var dirPath = Path.Combine(
+ using var reader = archive.ExtractAllEntries();
+ await reader.WriteAllToDirectoryAsync(
destinationDirectory,
- entry.Key.NotNull("Entry Key is null")
+ options,
+ cancellationToken
+ );
+ }
+ else
+ {
+ // For non-solid archives, extract entries directly
+ await archive.WriteToDirectoryAsyncInternal(
+ destinationDirectory,
+ options,
+ progress,
+ cancellationToken
);
- if (
- Path.GetDirectoryName(dirPath + "/") is { } parentDirectory
- && seenDirectories.Add(dirPath)
- )
- {
- Directory.CreateDirectory(parentDirectory);
- }
- continue;
}
-
- // Use the entry's WriteToDirectory method which respects ExtractionOptions
- entry.WriteToDirectory(destinationDirectory, options);
-
- // Update progress
- bytesRead += entry.Size;
- progress?.Report(new ProgressReport(entry.Key ?? string.Empty, bytesRead, totalBytes));
}
- }
-
- ///
- /// Extract to specific directory asynchronously with progress reporting and cancellation support
- ///
- /// The archive to extract.
- /// The folder to extract into.
- /// Extraction options.
- /// Optional progress reporter for tracking extraction progress.
- /// Optional cancellation token.
- public static async Task WriteToDirectoryAsync(
- this IArchive archive,
- string destinationDirectory,
- ExtractionOptions? options = null,
- IProgress? progress = null,
- CancellationToken cancellationToken = default
- )
- {
- // Prepare for progress reporting
- var totalBytes = archive.TotalUncompressSize;
- var bytesRead = 0L;
- // Tracking for created directories.
- var seenDirectories = new HashSet();
-
- // Extract
- foreach (var entry in archive.Entries)
+ private async Task WriteToDirectoryAsyncInternal(
+ string destinationDirectory,
+ ExtractionOptions? options,
+ IProgress? progress,
+ CancellationToken cancellationToken
+ )
{
- cancellationToken.ThrowIfCancellationRequested();
+ // Prepare for progress reporting
+ var totalBytes = archive.TotalUncompressSize;
+ var bytesRead = 0L;
+
+ // Tracking for created directories.
+ var seenDirectories = new HashSet();
- if (entry.IsDirectory)
+ // Extract
+ foreach (var entry in archive.Entries)
{
- var dirPath = Path.Combine(
- destinationDirectory,
- entry.Key.NotNull("Entry Key is null")
- );
- if (
- Path.GetDirectoryName(dirPath + "/") is { } parentDirectory
- && seenDirectories.Add(dirPath)
- )
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (entry.IsDirectory)
{
- Directory.CreateDirectory(parentDirectory);
+ var dirPath = Path.Combine(
+ destinationDirectory,
+ entry.Key.NotNull("Entry Key is null")
+ );
+ if (
+ Path.GetDirectoryName(dirPath + "/") is { } parentDirectory
+ && seenDirectories.Add(dirPath)
+ )
+ {
+ Directory.CreateDirectory(parentDirectory);
+ }
+ continue;
}
- continue;
- }
- // Use the entry's WriteToDirectoryAsync method which respects ExtractionOptions
- await entry
- .WriteToDirectoryAsync(destinationDirectory, options, cancellationToken)
- .ConfigureAwait(false);
+ // Use the entry's WriteToDirectoryAsync method which respects ExtractionOptions
+ await entry
+ .WriteToDirectoryAsync(destinationDirectory, options, cancellationToken)
+ .ConfigureAwait(false);
- // Update progress
- bytesRead += entry.Size;
- progress?.Report(new ProgressReport(entry.Key ?? string.Empty, bytesRead, totalBytes));
+ // Update progress
+ bytesRead += entry.Size;
+ progress?.Report(
+ new ProgressReport(entry.Key ?? string.Empty, bytesRead, totalBytes)
+ );
+ }
}
}
}