Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ await using (var reader = await ReaderFactory.OpenAsyncReader(stream))
// Async extraction of all entries
await reader.WriteAllToDirectoryAsync(
@"C:\output",
cancellationToken
cancellationToken: cancellationToken
);
}
```
Expand Down Expand Up @@ -231,11 +231,11 @@ using (var writer = WriterFactory.OpenWriter(stream, ArchiveType.Zip, Compressio

### ReaderOptions

Use factory presets and fluent helpers for common configurations:
Use preset properties and fluent helpers for common configurations:

```csharp
// External stream with password and custom encoding
var options = ReaderOptions.ForExternalStream()
var options = ReaderOptions.ForExternalStream
.WithPassword("password")
.WithArchiveEncoding(new ArchiveEncoding { Default = Encoding.GetEncoding(932) });

Expand All @@ -244,9 +244,14 @@ using (var archive = ZipArchive.OpenArchive("file.zip", options))
// ...
}

// Common presets
var safeOptions = ReaderOptions.SafeExtract; // No overwrite
var flatOptions = ReaderOptions.FlatExtract; // No directory structure
// Open-time presets
var external = ReaderOptions.ForExternalStream;
var owned = ReaderOptions.ForFilePath;

// Extraction presets
var safeOptions = ExtractionOptions.SafeExtract; // No overwrite
var flatOptions = ExtractionOptions.FlatExtract; // No directory structure
var metadataOptions = ExtractionOptions.PreserveMetadata; // Keep timestamps and attributes

// Factory defaults:
// - file path / FileInfo overloads use LeaveStreamOpen = false
Expand Down Expand Up @@ -297,23 +302,24 @@ archive.SaveTo("output.zip", options);
### Extraction behavior

```csharp
var options = new ReaderOptions
var options = new ExtractionOptions
{
ExtractFullPath = true, // Recreate directory structure
Overwrite = true, // Overwrite existing files
PreserveFileTime = true // Keep original timestamps
};

using (var archive = ZipArchive.OpenArchive("file.zip", options))
using (var archive = ZipArchive.OpenArchive("file.zip"))
{
archive.WriteToDirectory(@"C:\output");
archive.WriteToDirectory(@"C:\output", options);
}
```

### Options matrix

```text
ReaderOptions: open-time behavior (password, encoding, stream ownership, extraction defaults)
ReaderOptions: open-time behavior (password, encoding, stream ownership)
ExtractionOptions: extract-time behavior (overwrite, paths, timestamps, attributes, symlinks)
WriterOptions: write-time behavior (compression type/level, encoding, stream ownership)
ZipWriterEntryOptions: per-entry ZIP overrides (compression, level, timestamps, comments, zip64)
```
Expand All @@ -324,7 +330,7 @@ ZipWriterEntryOptions: per-entry ZIP overrides (compression, level, timestamps,

```csharp
var registry = CompressionProviderRegistry.Default.With(new SystemGZipCompressionProvider());
var readerOptions = ReaderOptions.ForOwnedFile().WithProviders(registry);
var readerOptions = ReaderOptions.ForFilePath.WithProviders(registry);
var writerOptions = new WriterOptions(CompressionType.GZip)
{
CompressionLevel = 6,
Expand Down Expand Up @@ -412,7 +418,7 @@ var progress = new Progress<ProgressReport>(report =>
Console.WriteLine($"Extracting {report.EntryPath}: {report.PercentComplete}%");
});

var options = ReaderOptions.ForOwnedFile().WithProgress(progress);
var options = ReaderOptions.ForFilePath.WithProgress(progress);
using (var archive = ZipArchive.OpenArchive("archive.zip", options))
{
archive.WriteToDirectory(@"C:\output");
Expand Down
3 changes: 2 additions & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ Common types, options, and enumerations used across formats.
- `ArchiveType.cs` - Enum for archive formats
- `CompressionType.cs` - Enum for compression methods
- `ArchiveEncoding.cs` - Character encoding configuration
- `IExtractionOptions.cs` - Extraction configuration exposed through `ReaderOptions`
- `IExtractionOptions.cs` - Interface for extraction configuration
- `ExtractionOptions.cs` - Extraction behavior options for file extraction APIs
- Format-specific headers: `Zip/Headers/`, `Tar/Headers/`, `Rar/Headers/`, etc.

#### `Compressors/` - Compression Algorithms
Expand Down
4 changes: 2 additions & 2 deletions docs/PERFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ using (var archive = ZipArchive.OpenArchive("archive.zip"))
{
await archive.WriteToDirectoryAsync(
@"C:\output",
cancellationToken
cancellationToken: cancellationToken
);
}
// Thread can handle other work while I/O happens
Expand Down Expand Up @@ -369,7 +369,7 @@ try
{
await archive.WriteToDirectoryAsync(
@"C:\output",
cts.Token
cancellationToken: cts.Token
);
}
}
Expand Down
31 changes: 16 additions & 15 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ SharpCompress now provides full async/await support for all I/O operations. All

**Key Async Methods:**
- `reader.WriteEntryToAsync(stream, cancellationToken)` - Extract entry asynchronously
- `reader.WriteAllToDirectoryAsync(path, cancellationToken)` - Extract all asynchronously
- `reader.WriteAllToDirectoryAsync(path, cancellationToken: cancellationToken)` - Extract all asynchronously
- `writer.WriteAsync(filename, stream, modTime, cancellationToken)` - Write entry asynchronously
- `writer.WriteAllAsync(directory, pattern, searchOption, cancellationToken)` - Write directory asynchronously
- `entry.OpenEntryStreamAsync(cancellationToken)` - Open entry stream asynchronously
Expand Down Expand Up @@ -94,14 +94,14 @@ Note: Extracting a solid rar or 7z file needs to be done in sequential order to
`ExtractAllEntries` is primarily intended for solid archives (like solid Rar) or 7Zip archives, where sequential extraction provides the best performance. For general/simple extraction with any supported archive type, use `archive.WriteToDirectory()` instead.

```C#
// Using fluent factory method for extraction options
using (var archive = RarArchive.OpenArchive("Test.rar",
ReaderOptions.ForOwnedFile()
.WithExtractFullPath(true)
.WithOverwrite(true)))
// Use ReaderOptions for open-time behavior and ExtractionOptions for extract-time behavior
using (var archive = RarArchive.OpenArchive("Test.rar", ReaderOptions.ForFilePath))
{
// Simple extraction with RarArchive; this WriteToDirectory pattern works for all archive types
archive.WriteToDirectory(@"D:\temp");
archive.WriteToDirectory(
@"D:\temp",
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
);
}
```

Expand Down Expand Up @@ -131,12 +131,13 @@ var progress = new Progress<ProgressReport>(report =>
});

using (var archive = RarArchive.OpenArchive("archive.rar",
ReaderOptions.ForOwnedFile()
.WithProgress(progress)
.WithExtractFullPath(true)
.WithOverwrite(true))) // Must be solid Rar or 7Zip
ReaderOptions.ForFilePath
.WithProgress(progress))) // Must be solid Rar or 7Zip
{
archive.WriteToDirectory(@"D:\output");
archive.WriteToDirectory(
@"D:\output",
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
);
}
```

Expand Down Expand Up @@ -218,7 +219,7 @@ To replace a specific algorithm (for example to use `System.IO.Compression` for
var systemGZip = new SystemGZipCompressionProvider();
var customRegistry = CompressionProviderRegistry.Default.With(systemGZip);

var readerOptions = ReaderOptions.ForOwnedFile()
var readerOptions = ReaderOptions.ForFilePath
.WithProviders(customRegistry);
using var reader = ReaderFactory.OpenReader(stream, readerOptions);

Expand Down Expand Up @@ -261,7 +262,7 @@ using (var reader = ReaderFactory.OpenReader(stream))
{
await reader.WriteAllToDirectoryAsync(
@"D:\temp",
cancellationToken
cancellationToken: cancellationToken
);
}
```
Expand Down Expand Up @@ -339,7 +340,7 @@ using (var archive = ZipArchive.OpenArchive("archive.zip"))
// Simple async extraction - works for all archive types
await archive.WriteToDirectoryAsync(
@"C:\output",
cancellationToken
cancellationToken: cancellationToken
);
}
```
Expand Down
4 changes: 2 additions & 2 deletions src/SharpCompress/Archives/ArchiveFactory.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static async ValueTask<IAsyncArchive> OpenAsyncArchive(
CancellationToken cancellationToken = default
)
{
options ??= ReaderOptions.ForOwnedFile;
options ??= ReaderOptions.ForFilePath;

var factory = await FindFactoryAsync<IArchiveFactory>(fileInfo, cancellationToken)
.ConfigureAwait(false);
Expand Down Expand Up @@ -73,7 +73,7 @@ public static async ValueTask<IAsyncArchive> OpenAsyncArchive(
}

fileInfo.NotNull(nameof(fileInfo));
options ??= ReaderOptions.ForOwnedFile;
options ??= ReaderOptions.ForFilePath;

var factory = await FindFactoryAsync<IMultiArchiveFactory>(fileInfo, cancellationToken)
.ConfigureAwait(false);
Expand Down
10 changes: 5 additions & 5 deletions src/SharpCompress/Archives/ArchiveFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static IArchive OpenArchive(string filePath, ReaderOptions? options = nul

public static IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? options = null)
{
options ??= ReaderOptions.ForOwnedFile;
options ??= ReaderOptions.ForFilePath;

return FindFactory<IArchiveFactory>(fileInfo).OpenArchive(fileInfo, options);
}
Expand All @@ -64,7 +64,7 @@ public static IArchive OpenArchive(
}

fileInfo.NotNull(nameof(fileInfo));
options ??= ReaderOptions.ForOwnedFile;
options ??= ReaderOptions.ForFilePath;

return FindFactory<IMultiArchiveFactory>(fileInfo).OpenArchive(filesArray, options);
}
Expand Down Expand Up @@ -93,11 +93,11 @@ public static IArchive OpenArchive(IEnumerable<Stream> streams, ReaderOptions? o
public static void WriteToDirectory(
string sourceArchive,
string destinationDirectory,
ReaderOptions? options = null
ExtractionOptions? options = null
)
{
using var archive = OpenArchive(sourceArchive, options);
archive.WriteToDirectory(destinationDirectory);
using var archive = OpenArchive(sourceArchive);
archive.WriteToDirectory(destinationDirectory, options);
}

public static T FindFactory<T>(string path)
Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/Archives/IArchive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public interface IArchive : IDisposable
ArchiveType Type { get; }

/// <summary>
/// The options used when opening this archive, including extraction behavior settings.
/// The options used when opening this archive.
/// </summary>
ReaderOptions ReaderOptions { get; }

Expand Down
17 changes: 13 additions & 4 deletions src/SharpCompress/Archives/IArchiveEntryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,37 +102,44 @@ private static Stream WrapWithProgress(
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public void WriteToDirectory(string destinationDirectory) =>
public void WriteToDirectory(
string destinationDirectory,
ExtractionOptions? options = null
) =>
ExtractionMethods.WriteEntryToDirectory(
entry,
destinationDirectory,
(path) => entry.WriteToFile(path)
options,
(path) => entry.WriteToFile(path, options)
);

/// <summary>
/// Extract to specific directory asynchronously, retaining filename
/// </summary>
public async ValueTask WriteToDirectoryAsync(
string destinationDirectory,
ExtractionOptions? options = null,
CancellationToken cancellationToken = default
) =>
await ExtractionMethods
.WriteEntryToDirectoryAsync(
entry,
destinationDirectory,
options,
async (path, ct) =>
await entry.WriteToFileAsync(path, ct).ConfigureAwait(false),
await entry.WriteToFileAsync(path, options, ct).ConfigureAwait(false),
cancellationToken
)
.ConfigureAwait(false);

/// <summary>
/// Extract to specific file
/// </summary>
public void WriteToFile(string destinationFileName) =>
public void WriteToFile(string destinationFileName, ExtractionOptions? options = null) =>
ExtractionMethods.WriteEntryToFile(
entry,
destinationFileName,
options,
(x, fm) =>
{
using var fs = File.Open(destinationFileName, fm);
Expand All @@ -145,12 +152,14 @@ public void WriteToFile(string destinationFileName) =>
/// </summary>
public async ValueTask WriteToFileAsync(
string destinationFileName,
ExtractionOptions? options = null,
CancellationToken cancellationToken = default
) =>
await ExtractionMethods
.WriteEntryToFileAsync(
entry,
destinationFileName,
options,
async (x, fm, ct) =>
{
using var fs = File.Open(destinationFileName, fm);
Expand Down
9 changes: 6 additions & 3 deletions src/SharpCompress/Archives/IArchiveExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,28 @@ public static class IArchiveExtensions
/// Extract to specific directory with progress reporting
/// </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>
public void WriteToDirectory(
string destinationDirectory,
ExtractionOptions? options = null,
IProgress<ProgressReport>? progress = null
)
{
if (archive.IsSolid || archive.Type == ArchiveType.SevenZip)
{
using var reader = archive.ExtractAllEntries();
reader.WriteAllToDirectory(destinationDirectory);
reader.WriteAllToDirectory(destinationDirectory, options);
}
else
{
archive.WriteToDirectoryInternal(destinationDirectory, progress);
archive.WriteToDirectoryInternal(destinationDirectory, options, progress);
}
}

private void WriteToDirectoryInternal(
string destinationDirectory,
ExtractionOptions? options,
IProgress<ProgressReport>? progress
)
{
Expand All @@ -58,7 +61,7 @@ private void WriteToDirectoryInternal(
continue;
}

entry.WriteToDirectory(destinationDirectory);
entry.WriteToDirectory(destinationDirectory, options);

bytesRead += entry.Size;
progress?.Report(
Expand Down
Loading