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
123 changes: 84 additions & 39 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ using (var archive = RarArchive.OpenArchive("file.rar"))
using (var archive = SevenZipArchive.OpenArchive("file.7z"))
using (var archive = GZipArchive.OpenArchive("file.gz"))

// With options
var options = new ReaderOptions
// With fluent options (preferred)
var options = ReaderOptions.ForEncryptedArchive("password")
.WithArchiveEncoding(new ArchiveEncoding { Default = Encoding.GetEncoding(932) });
using (var archive = ZipArchive.OpenArchive("encrypted.zip", options))

// Alternative: object initializer
var options2 = new ReaderOptions
{
Password = "password",
LeaveStreamOpen = true,
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(932) }
};
using (var archive = ZipArchive.OpenArchive("encrypted.zip", options))
```

### Creating Archives
Expand All @@ -44,16 +48,21 @@ using (var archive = ZipArchive.CreateArchive())
using (var archive = TarArchive.CreateArchive())
using (var archive = GZipArchive.CreateArchive())

// With options
var options = new WriterOptions(CompressionType.Deflate)
{
CompressionLevel = 9,
LeaveStreamOpen = false
};
// With fluent options (preferred)
var options = WriterOptions.ForZip()
.WithCompressionLevel(9)
.WithLeaveStreamOpen(false);
using (var archive = ZipArchive.CreateArchive())
{
archive.SaveTo("output.zip", options);
}

// Alternative: constructor with object initializer
var options2 = new WriterOptions(CompressionType.Deflate)
{
CompressionLevel = 9,
LeaveStreamOpen = false
};
```

---
Expand All @@ -72,16 +81,11 @@ using (var archive = ZipArchive.OpenArchive("file.zip"))
var entry = archive.Entries.FirstOrDefault(e => e.Key == "file.txt");

// Extract all
archive.WriteToDirectory(@"C:\output", new ExtractionOptions
{
ExtractFullPath = true,
Overwrite = true
});
archive.WriteToDirectory(@"C:\output");

// Extract single entry
var entry = archive.Entries.First();
entry.WriteToFile(@"C:\output\file.txt");
entry.WriteToFile(@"C:\output\file.txt", new ExtractionOptions { Overwrite = true });

// Get entry stream
using (var stream = entry.OpenEntryStream())
Expand All @@ -95,7 +99,6 @@ using (var asyncArchive = await ZipArchive.OpenAsyncArchive("file.zip"))
{
await asyncArchive.WriteToDirectoryAsync(
@"C:\output",
new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
cancellationToken: cancellationToken
);
}
Expand Down Expand Up @@ -187,7 +190,6 @@ using (var reader = await ReaderFactory.OpenAsyncReader(stream))
// Async extraction of all entries
await reader.WriteAllToDirectoryAsync(
@"C:\output",
new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
cancellationToken
);
}
Expand Down Expand Up @@ -229,43 +231,91 @@ using (var writer = WriterFactory.OpenWriter(stream, ArchiveType.Zip, Compressio

### ReaderOptions

Use factory presets and fluent helpers for common configurations:

```csharp
var options = new ReaderOptions
{
Password = "password", // For encrypted archives
LeaveStreamOpen = true, // Don't close wrapped stream
ArchiveEncoding = new ArchiveEncoding // Custom character encoding
{
Default = Encoding.GetEncoding(932)
}
};
// External stream with password and custom encoding
var options = ReaderOptions.ForExternalStream()
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs use ReaderOptions.ForExternalStream() here, but ForExternalStream is a property, not a method. Update the sample to ReaderOptions.ForExternalStream (no parentheses) so it compiles.

Suggested change
var options = ReaderOptions.ForExternalStream()
var options = ReaderOptions.ForExternalStream

Copilot uses AI. Check for mistakes.
.WithPassword("password")
.WithArchiveEncoding(new ArchiveEncoding { Default = Encoding.GetEncoding(932) });

using (var archive = ZipArchive.OpenArchive("file.zip", options))
{
// ...
}

// Common presets
var safeOptions = ReaderOptions.SafeExtract; // No overwrite
var flatOptions = ReaderOptions.FlatExtract; // No directory structure

// Factory defaults:
// - file path / FileInfo overloads use LeaveStreamOpen = false
// - stream overloads use LeaveStreamOpen = true
```

Alternative: traditional object initializer:

```csharp
var options = new ReaderOptions
{
Password = "password",
LeaveStreamOpen = true,
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(932) }
};
```

### WriterOptions

Factory methods provide a clean, discoverable way to create writer options:

```csharp
// Factory methods for common archive types
var zipOptions = WriterOptions.ForZip() // ZIP with Deflate
.WithCompressionLevel(9) // 0-9 for Deflate
.WithLeaveStreamOpen(false); // Close stream when done

var tarOptions = WriterOptions.ForTar(CompressionType.GZip) // TAR with GZip
.WithLeaveStreamOpen(false);

var gzipOptions = WriterOptions.ForGZip() // GZip file
.WithCompressionLevel(6);

archive.SaveTo("output.zip", zipOptions);
```

Alternative: traditional constructor with object initializer:

```csharp
var options = new WriterOptions(CompressionType.Deflate)
{
CompressionLevel = 9, // 0-9 for Deflate
LeaveStreamOpen = true, // Don't close stream
CompressionLevel = 9,
LeaveStreamOpen = true,
};
archive.SaveTo("output.zip", options);
```

### ExtractionOptions
### Extraction behavior

```csharp
var options = new ExtractionOptions
var options = new ReaderOptions
{
ExtractFullPath = true, // Recreate directory structure
Overwrite = true, // Overwrite existing files
PreserveFileTime = true // Keep original timestamps
};
archive.WriteToDirectory(@"C:\output", options);

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

### Options matrix

```text
ReaderOptions: open-time behavior (password, encoding, stream ownership, extraction defaults)
WriterOptions: write-time behavior (compression type/level, encoding, stream ownership)
ZipWriterEntryOptions: per-entry ZIP overrides (compression, level, timestamps, comments, zip64)
```

---
Expand Down Expand Up @@ -317,13 +367,9 @@ ArchiveType.ZStandard
try
{
using (var archive = ZipArchive.Open("archive.zip",
new ReaderOptions { Password = "password" }))
ReaderOptions.ForEncryptedArchive("password")))
{
archive.WriteToDirectory(@"C:\output", new ExtractionOptions
{
ExtractFullPath = true,
Overwrite = true
});
archive.WriteToDirectory(@"C:\output");
}
}
catch (PasswordRequiredException)
Expand All @@ -348,7 +394,7 @@ var progress = new Progress<ProgressReport>(report =>
Console.WriteLine($"Extracting {report.EntryPath}: {report.PercentComplete}%");
});

var options = new ReaderOptions { Progress = progress };
var options = ReaderOptions.ForOwnedFile().WithProgress(progress);
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sample uses ReaderOptions.ForOwnedFile() but ForOwnedFile is a property. As written, the snippet won’t compile; use ReaderOptions.ForOwnedFile before chaining fluent helpers.

Suggested change
var options = ReaderOptions.ForOwnedFile().WithProgress(progress);
var options = ReaderOptions.ForOwnedFile.WithProgress(progress);

Copilot uses AI. Check for mistakes.
using (var archive = ZipArchive.OpenArchive("archive.zip", options))
{
archive.WriteToDirectory(@"C:\output");
Expand All @@ -367,7 +413,6 @@ try
{
await archive.WriteToDirectoryAsync(
@"C:\output",
new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
cancellationToken: cts.Token
);
}
Expand Down
14 changes: 6 additions & 8 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ 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
- `ExtractionOptions.cs` - Extraction configuration
- `IExtractionOptions.cs` - Extraction configuration exposed through `ReaderOptions`
- Format-specific headers: `Zip/Headers/`, `Tar/Headers/`, `Rar/Headers/`, etc.

#### `Compressors/` - Compression Algorithms
Expand Down Expand Up @@ -215,13 +215,13 @@ using (var compressor = new DeflateStream(nonDisposingStream))
public abstract class AbstractArchive : IArchive
{
// Template methods
public virtual void WriteToDirectory(string destinationDirectory, ExtractionOptions options)
public virtual void WriteToDirectory(string destinationDirectory)
{
// Common extraction logic
foreach (var entry in Entries)
{
// Call subclass method
entry.WriteToFile(destinationPath, options);
entry.WriteToFile(destinationPath);
}
}

Expand Down Expand Up @@ -267,8 +267,7 @@ public interface IArchive : IDisposable
{
IEnumerable<IEntry> Entries { get; }

void WriteToDirectory(string destinationDirectory,
ExtractionOptions options = null);
void WriteToDirectory(string destinationDirectory);

IEntry FirstOrDefault(Func<IEntry, bool> predicate);

Expand All @@ -287,8 +286,7 @@ public interface IReader : IDisposable

bool MoveToNextEntry();

void WriteEntryToDirectory(string destinationDirectory,
ExtractionOptions options = null);
void WriteEntryToDirectory(string destinationDirectory);

Stream OpenEntryStream();

Expand Down Expand Up @@ -327,7 +325,7 @@ public interface IEntry
DateTime? LastModifiedTime { get; }
CompressionType CompressionType { get; }

void WriteToFile(string fullPath, ExtractionOptions options = null);
void WriteToFile(string fullPath);
void WriteToStream(Stream destinationStream);
Stream OpenEntryStream();

Expand Down
35 changes: 14 additions & 21 deletions docs/ENCODING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,9 @@ Most archive formats store filenames and metadata as bytes. SharpCompress must c
using SharpCompress.Common;
using SharpCompress.Readers;

// Configure encoding before opening archive
var options = new ReaderOptions
{
ArchiveEncoding = new ArchiveEncoding
{
Default = Encoding.GetEncoding(932) // cp932 for Japanese
}
};
// Configure encoding using fluent factory method (preferred)
var options = ReaderOptions.ForEncoding(
new ArchiveEncoding { Default = Encoding.GetEncoding(932) }); // cp932 for Japanese

using (var archive = ZipArchive.OpenArchive("japanese.zip", options))
{
Expand All @@ -34,6 +29,12 @@ using (var archive = ZipArchive.OpenArchive("japanese.zip", options))
Console.WriteLine(entry.Key); // Now shows correct characters
}
}

// Alternative: object initializer
var options2 = new ReaderOptions
{
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(932) }
};
```

### ArchiveEncoding Properties
Expand All @@ -47,10 +48,8 @@ using (var archive = ZipArchive.OpenArchive("japanese.zip", options))

**Archive API:**
```csharp
var options = new ReaderOptions
{
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(932) }
};
var options = ReaderOptions.ForEncoding(
new ArchiveEncoding { Default = Encoding.GetEncoding(932) });
using (var archive = ZipArchive.OpenArchive("file.zip", options))
{
// Use archive with correct encoding
Expand All @@ -59,10 +58,8 @@ using (var archive = ZipArchive.OpenArchive("file.zip", options))

**Reader API:**
```csharp
var options = new ReaderOptions
{
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(932) }
};
var options = ReaderOptions.ForEncoding(
new ArchiveEncoding { Default = Encoding.GetEncoding(932) });
using (var stream = File.OpenRead("file.zip"))
using (var reader = ReaderFactory.OpenReader(stream, options))
{
Expand Down Expand Up @@ -390,11 +387,7 @@ var options = new ReaderOptions

using (var archive = ZipArchive.OpenArchive("japanese_files.zip", options))
{
archive.WriteToDirectory(@"C:\output", new ExtractionOptions
{
ExtractFullPath = true,
Overwrite = true
});
archive.WriteToDirectory(@"C:\output");
}
// Files extracted with correct Japanese names
```
Expand Down
13 changes: 2 additions & 11 deletions docs/PERFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,7 @@ using (var archive = RarArchive.OpenArchive("solid.rar"))
using (var archive = RarArchive.OpenArchive("solid.rar"))
{
// Method 1: Use WriteToDirectory (recommended)
archive.WriteToDirectory(@"C:\output", new ExtractionOptions
{
ExtractFullPath = true,
Overwrite = true
});
archive.WriteToDirectory(@"C:\output");

// Method 2: Use ExtractAllEntries
archive.ExtractAllEntries();
Expand Down Expand Up @@ -337,7 +333,6 @@ using (var archive = ZipArchive.OpenArchive("archive.zip"))
{
await archive.WriteToDirectoryAsync(
@"C:\output",
new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
cancellationToken
);
}
Expand All @@ -355,10 +350,7 @@ Async doesn't improve performance for:
// Sync extraction (simpler, same performance on fast I/O)
using (var archive = ZipArchive.OpenArchive("archive.zip"))
{
archive.WriteToDirectory(
@"C:\output",
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
);
archive.WriteToDirectory(@"C:\output");
}
// Simple and fast - no async needed
```
Expand All @@ -377,7 +369,6 @@ try
{
await archive.WriteToDirectoryAsync(
@"C:\output",
new ExtractionOptions { ExtractFullPath = true, Overwrite = true },
cts.Token
);
}
Expand Down
Loading