2026-01-08 15:34:48 +00:00
# API Quick Reference
Quick reference for commonly used SharpCompress APIs.
## Factory Methods
### Opening Archives
```csharp
// Auto-detect format
2026-01-15 13:29:57 +00:00
using (var reader = ReaderFactory.OpenReader(stream))
2026-01-08 15:34:48 +00:00
{
2026-09-22 01:40:55 +01:00
// Works with Zip, Tar, GZip, Rar, etc. Reading 7Zip needs the Archive API
2026-01-08 15:34:48 +00:00
}
// Specific format - Archive API
2026-01-15 13:29:57 +00:00
using (var archive = ZipArchive.OpenArchive("file.zip"))
using (var archive = TarArchive.OpenArchive("file.tar"))
using (var archive = RarArchive.OpenArchive("file.rar"))
using (var archive = SevenZipArchive.OpenArchive("file.7z"))
using (var archive = GZipArchive.OpenArchive("file.gz"))
2026-01-08 15:34:48 +00:00
2026-02-10 11:10:04 +00:00
// 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
2026-01-12 16:08:16 +00:00
{
2026-01-08 15:34:48 +00:00
Password = "password",
LeaveStreamOpen = true,
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(932) }
};
```
2026-06-06 15:50:49 +01:00
```csharp
// Auto-detect and open with the Archive API
using (var archive = ArchiveFactory.OpenArchive("archive.zip"))
{
foreach (var entry in archive.Entries)
{
Console.WriteLine(entry.Key);
}
}
2026-10-21 11:47:47 +01:00
// Detect before opening (using SharpCompress.Detection)
if (ArchiveDetector.IsArchive("archive.zip", out var archiveType))
2026-06-06 15:50:49 +01:00
{
Console.WriteLine($"Detected {archiveType}");
}
2026-08-04 11:45:13 +01:00
// Detect the format and choose an API without enumerating entries.
2026-10-21 11:47:47 +01:00
var detection = ArchiveDetector.DetectArchive("archive.tar.xz");
2026-08-04 11:45:13 +01:00
if (detection is not null)
2026-06-06 15:50:49 +01:00
{
2026-08-04 11:45:13 +01:00
Console.WriteLine($"Container: {detection.ContainerType}");
Console.WriteLine($"Outer compression: {detection.OuterCompressionType}");
Console.WriteLine($"Supported APIs: {detection.SupportedApis}");
2026-06-06 15:50:49 +01:00
}
2026-08-04 11:45:13 +01:00
// InspectArchive parses complete archive metadata. It can be expensive for
// sequential formats such as TAR and compressed TAR.
2026-10-21 11:47:47 +01:00
var information = ArchiveInspector.InspectArchive("archive.zip");
2026-08-04 11:45:13 +01:00
if (information is not null)
{
Console.WriteLine($"Entries: {information.EntryCount}");
Console.WriteLine($"Solid streams: {information.SolidStreamCount}");
2026-08-05 16:20:08 +01:00
Console.WriteLine($"Some ZIP entry sizes arrive after their data: {information.Zip?.HasEntriesWithDeferredSizes}");
2026-08-04 11:45:13 +01:00
}
2026-10-21 11:47:47 +01:00
var asyncInformation = await ArchiveInspector.InspectArchiveAsync("archive.zip", cancellationToken);
2026-06-06 15:50:49 +01:00
// Multi-volume archives
var parts = ArchiveFactory.GetFileParts("archive.part1.rar")
.Select(path => new FileInfo(path))
.ToArray();
using (var archive = ArchiveFactory.OpenArchive(parts))
{
archive.WriteToDirectory(@"C:\output");
}
```
2026-08-04 11:45:13 +01:00
`DetectArchive` identifies the logical container, its outer compression wrapper, and whether the Archive and Reader APIs are available without enumerating entries. Compressed TAR wrappers such as `.tar.gz` and `.tar.xz` are identified as `ArchiveType.Tar` with an outer compression type and `ArchiveAccessMode.Reader` .
`InspectArchive` enumerates metadata and returns `ArchiveInformation` . It reports `Partial` status for missing volumes or encrypted headers without a password; malformed archives and incorrect passwords throw. ZIP-specific metadata is exposed through `ArchiveInformation.Zip` .
2026-10-21 11:47:47 +01:00
Detection and inspection entry points and result types are in the `SharpCompress.Detection` namespace.
`ArchiveDetector` also exposes `FindFactory<T>` , `IsArchive` , and `IsArchiveAsync` . `SharpCompress.Archives.ArchiveExtractor.WriteToDirectory(sourceArchive, destinationDirectory, options)` extracts an archive from a file path. The existing `ArchiveFactory` versions of these methods remain available for compatibility but are marked obsolete with warnings directing callers to the replacements. Opening, creating archives, and discovering file parts remain on `ArchiveFactory` .
2026-08-06 09:13:22 +01:00
2026-08-04 11:45:13 +01:00
The stream overloads of `DetectArchive` and `InspectArchive` preserve the supplied stream's position and leave it open, including when `ReaderOptions.LeaveStreamOpen` is `false` .
#### Migrating from `GetArchiveInformation`
| Removed API | Replacement |
| --- | --- |
2026-10-21 11:47:47 +01:00
| `GetArchiveInformation(...)` used only to identify a format | `ArchiveDetector.DetectArchive(...)` |
| `GetArchiveInformation(...)` used to enumerate archive details | `ArchiveInspector.InspectArchive(...)` |
| `GetArchiveInformationAsync(...)` | `ArchiveDetector.DetectArchiveAsync(...)` or `ArchiveInspector.InspectArchiveAsync(...)` |
2026-08-04 11:45:13 +01:00
| `Type` | `Detection.ContainerType` |
| `SupportsRandomAccess` | `Detection.SupportedApis.HasFlag(ArchiveAccessMode.Archive)` |
2026-08-05 16:20:08 +01:00
| `ZipDataDescriptorEntryCount` | `Zip.HasEntriesWithDeferredSizes` |
2026-08-04 11:45:13 +01:00
| `SolidStreamCount` | `SolidStreamCount` |
2026-06-06 15:50:49 +01:00
2026-10-19 14:10:30 +01:00
### RAR Entry Integrity
RAR Archive and Reader entry streams validate CRC32 (or RAR5 BLAKE2sp when
present) on both synchronous and asynchronous extraction paths. Drain an entry
stream to the end to perform validation; a mismatch throws
2026-10-20 11:11:43 +01:00
`InvalidFormatException` . Entries without a checksum are extracted without
checksum validation. Disposing a partially read Archive entry stream does not
validate the unread payload. Reader entry streams normally drain unread data
on disposal (synchronous or asynchronous) unless the reader is cancelled, so
disposal can validate the checksum and throw on a mismatch.
Encrypted entries retain the existing checksum-checking
2026-10-19 14:10:30 +01:00
limitations; this does not add authentication for encrypted RAR data.
2026-10-02 13:33:50 +01:00
### RAR5 Archive Comments
`SharpCompress.Common.Rar.RarVolume.Comment` exposes UTF-8 archive comments, including encrypted comments when `ReaderOptions.Password` is supplied. Comments are loaded while entries are enumerated; the property can be `null` before enumeration or when no comment is present.
2026-10-05 10:48:34 +01:00
Stored (compression method 0) comments are supported up to 16 MiB of unpacked data; larger or unknown-size comments throw `InvalidFormatException` . Comments using other compression methods are skipped without affecting entry extraction.
2026-10-13 12:23:24 +01:00
Truncated encrypted comment data throws `InvalidFormatException` on both synchronous and asynchronous reads. RAR5 KDF counts above 24 are rejected with `CryptographicException` before deriving encryption keys.
2026-10-10 08:22:55 +01:00
2026-10-02 13:33:50 +01:00
```csharp
using var archive = RarArchive.OpenArchive(
"encrypted.rar",
ReaderOptions.ForFilePath.WithPassword("password")
);
foreach (var entry in archive.Entries)
{
Console.WriteLine(entry.Key);
}
foreach (var volume in archive.Volumes.OfType<SharpCompress.Common.Rar.RarVolume>())
{
Console.WriteLine(volume.Comment);
}
```
2026-01-08 15:34:48 +00:00
### Creating Archives
```csharp
// Writer Factory
2026-01-15 13:29:57 +00:00
using (var writer = WriterFactory.OpenWriter(stream, ArchiveType.Zip, CompressionType.Deflate))
2026-01-08 15:34:48 +00:00
{
// Write entries
}
// Specific writer
2026-01-15 13:04:09 +00:00
using (var archive = ZipArchive.CreateArchive())
using (var archive = TarArchive.CreateArchive())
using (var archive = GZipArchive.CreateArchive())
2026-01-08 15:34:48 +00:00
2026-02-10 11:10:04 +00:00
// With fluent options (preferred)
var options = WriterOptions.ForZip()
.WithCompressionLevel(9)
2026-06-12 14:41:05 +01:00
.WithLeaveStreamOpen(false)
.WithBufferSize(131072);
2026-01-15 13:04:09 +00:00
using (var archive = ZipArchive.CreateArchive())
2026-01-08 15:34:48 +00:00
{
archive.SaveTo("output.zip", options);
}
2026-02-10 11:10:04 +00:00
// Alternative: constructor with object initializer
var options2 = new WriterOptions(CompressionType.Deflate)
{
CompressionLevel = 9,
2026-06-12 14:41:05 +01:00
LeaveStreamOpen = false,
BufferSize = 131072
2026-02-10 11:10:04 +00:00
};
2026-01-08 15:34:48 +00:00
```
2026-06-12 14:41:05 +01:00
`WriterOptions.BufferSize` controls stream copy buffers used while writing archive entries. If it is not set, SharpCompress falls back to `Constants.BufferSize` .
2026-01-08 15:34:48 +00:00
---
## Archive API Methods
### Reading/Extracting
```csharp
2026-01-15 13:29:57 +00:00
using (var archive = ZipArchive.OpenArchive("file.zip"))
2026-01-08 15:34:48 +00:00
{
// Get all entries
2026-01-12 16:08:16 +00:00
IEnumerable<IArchiveEntry> entries = archive.Entries;
2026-01-08 15:34:48 +00:00
// Find specific entry
var entry = archive.Entries.FirstOrDefault(e => e.Key == "file.txt");
2026-01-12 16:08:16 +00:00
2026-01-08 15:34:48 +00:00
// Extract all
2026-02-10 10:48:42 +00:00
archive.WriteToDirectory(@"C:\output");
2026-01-12 16:08:16 +00:00
2026-01-08 15:34:48 +00:00
// Extract single entry
2026-04-10 17:47:33 +01:00
var firstEntry = archive.Entries.First();
firstEntry.WriteToFile(@"C:\output\file.txt");
2026-01-12 16:08:16 +00:00
2026-06-18 17:06:16 +01:00
// Extract single entry to a stream with extraction options
using (var outputStream = File.Create(@"C:\output\file.txt"))
{
firstEntry.WriteTo(
outputStream,
new ExtractionOptions { CheckCrc = false }
);
}
2026-01-08 15:34:48 +00:00
// Get entry stream
using (var stream = entry.OpenEntryStream())
{
stream.CopyTo(outputStream);
}
}
2026-01-12 16:08:16 +00:00
// Async extraction (requires IAsyncArchive)
2026-02-12 10:32:20 +00:00
await using (var asyncArchive = await ZipArchive.OpenAsyncArchive("file.zip"))
2026-01-12 16:08:16 +00:00
{
2026-04-10 17:47:33 +01:00
// Extract all entries asynchronously
2026-01-12 16:08:16 +00:00
await asyncArchive.WriteToDirectoryAsync(
@"C:\output",
cancellationToken: cancellationToken
);
}
2026-04-10 17:47:33 +01:00
// Open a specific entry stream asynchronously
await using (var asyncArchive = await ZipArchive.OpenAsyncArchive("file.zip"))
2026-01-08 15:34:48 +00:00
{
2026-04-10 17:47:33 +01:00
await foreach (var entry in asyncArchive.EntriesAsync)
{
2026-06-18 17:06:16 +01:00
await using (var outputStream = File.Create(@"C:\output\" + entry.Key))
{
await entry.WriteToAsync(
outputStream,
new ExtractionOptions { CheckCrc = false },
cancellationToken: cancellationToken
);
}
2026-04-10 17:47:33 +01:00
using (var stream = await entry.OpenEntryStreamAsync(cancellationToken))
{
// ...
}
}
2026-01-08 15:34:48 +00:00
}
```
### Entry Properties
```csharp
foreach (var entry in archive.Entries)
{
string name = entry.Key; // Entry name/path
long size = entry.Size; // Uncompressed size
long compressedSize = entry.CompressedSize;
bool isDir = entry.IsDirectory;
DateTime? modTime = entry.LastModifiedTime;
CompressionType compression = entry.CompressionType;
}
```
### Creating Archives
```csharp
2026-01-15 13:04:09 +00:00
using (var archive = ZipArchive.CreateArchive())
2026-01-08 15:34:48 +00:00
{
// Add file
2026-01-12 16:08:16 +00:00
archive.AddEntry("file.txt", @"C:\source\file.txt");
2026-01-08 15:34:48 +00:00
// Add multiple files
2026-01-12 16:08:16 +00:00
archive.AddAllFromDirectory(@"C:\source");
archive.AddAllFromDirectory(@"C:\source", "*.txt"); // Pattern
2026-01-08 15:34:48 +00:00
// Save to file
archive.SaveTo("output.zip", CompressionType.Deflate);
2026-01-12 16:08:16 +00:00
2026-01-08 15:34:48 +00:00
// Save to stream
archive.SaveTo(outputStream, new WriterOptions(CompressionType.Deflate)
{
CompressionLevel = 9,
LeaveStreamOpen = true
});
}
```
---
## Reader API Methods
### Forward-Only Reading
```csharp
using (var stream = File.OpenRead("file.zip"))
2026-01-15 13:29:57 +00:00
using (var reader = ReaderFactory.OpenReader(stream))
2026-01-08 15:34:48 +00:00
{
while (reader.MoveToNextEntry())
{
2026-09-22 01:40:55 +01:00
IEntry entry = reader.Entry;
2026-01-12 16:08:16 +00:00
2026-01-08 15:34:48 +00:00
if (!entry.IsDirectory)
{
// Extract entry
reader.WriteEntryToDirectory(@"C:\output");
reader.WriteEntryToFile(@"C:\output\file.txt");
2026-01-12 16:08:16 +00:00
2026-01-08 15:34:48 +00:00
// Or get stream
using (var entryStream = reader.OpenEntryStream())
{
entryStream.CopyTo(outputStream);
}
}
}
}
2026-01-15 13:04:09 +00:00
// Async variants (use OpenAsyncReader to get IAsyncReader)
2026-01-12 16:08:16 +00:00
using (var stream = File.OpenRead("file.zip"))
2026-02-12 10:32:20 +00:00
await using (var reader = await ReaderFactory.OpenAsyncReader(stream))
2026-01-08 15:34:48 +00:00
{
2026-01-12 16:08:16 +00:00
while (await reader.MoveToNextEntryAsync())
{
await reader.WriteEntryToFileAsync(
@"C:\output\" + reader.Entry.Key,
cancellationToken: cancellationToken
);
}
2026-01-08 15:34:48 +00:00
2026-01-12 16:08:16 +00:00
// Async extraction of all entries
await reader.WriteAllToDirectoryAsync(
@"C:\output",
2026-03-02 07:00:33 +00:00
cancellationToken: cancellationToken
2026-01-12 16:08:16 +00:00
);
}
2026-01-08 15:34:48 +00:00
```
---
## Writer API Methods
### Creating Archives (Streaming)
```csharp
using (var stream = File.Create("output.zip"))
2026-01-15 13:29:57 +00:00
using (var writer = WriterFactory.OpenWriter(stream, ArchiveType.Zip, CompressionType.Deflate))
2026-01-08 15:34:48 +00:00
{
// Write single file
using (var fileStream = File.OpenRead("source.txt"))
{
writer.Write("entry.txt", fileStream, DateTime.Now);
}
// Write directory
writer.WriteAll("C:\\source", "*", SearchOption.AllDirectories);
writer.WriteAll("C:\\source", "*.txt", SearchOption.TopDirectoryOnly);
}
2026-04-10 17:47:33 +01:00
// Async variants: use OpenAsyncWriter to get IAsyncWriter
await using var stream = File.Create("output.zip");
await using var writer = await WriterFactory.OpenAsyncWriter(stream, ArchiveType.Zip, new WriterOptions(CompressionType.Deflate), cancellationToken);
using (var fileStream = File.OpenRead("source.txt"))
{
await writer.WriteAsync("entry.txt", fileStream, DateTime.Now, cancellationToken);
}
await writer.WriteAllAsync("C:\\source", "*", SearchOption.AllDirectories, cancellationToken);
2026-01-08 15:34:48 +00:00
```
---
## Common Options
### ReaderOptions
2026-03-03 12:50:27 +00:00
Use preset properties and fluent helpers for common configurations:
2026-02-10 11:10:04 +00:00
2026-01-08 15:34:48 +00:00
```csharp
2026-02-10 11:10:04 +00:00
// External stream with password and custom encoding
2026-03-03 12:50:27 +00:00
var options = ReaderOptions.ForExternalStream
2026-02-10 11:10:04 +00:00
.WithPassword("password")
.WithArchiveEncoding(new ArchiveEncoding { Default = Encoding.GetEncoding(932) });
2026-01-15 13:29:57 +00:00
using (var archive = ZipArchive.OpenArchive("file.zip", options))
2026-01-08 15:34:48 +00:00
{
// ...
}
2026-02-10 10:48:42 +00:00
2026-03-02 07:00:33 +00:00
// Open-time presets
var external = ReaderOptions.ForExternalStream;
2026-03-03 12:40:58 +00:00
var owned = ReaderOptions.ForFilePath;
2026-06-06 15:50:49 +01:00
var encrypted = ReaderOptions.ForEncryptedArchive("password");
var encoded = ReaderOptions.ForEncoding(new ArchiveEncoding { Default = Encoding.UTF8 });
var sfx = ReaderOptions.ForSelfExtractingArchive("password");
// Faster detection when the container is known
var hinted = ReaderOptions.ForExternalStream.WithExtensionHint("tar.gz");
// Increase for non-seekable streams with large detection probes, such as SFX RAR
var buffered = ReaderOptions.ForExternalStream.WithRewindableBufferSize(1_048_576);
2026-03-02 07:00:33 +00:00
2026-08-02 18:08:51 +02:00
// Opt in to formats' optional parallel decode (e.g. 7-Zip's automatic parallel LZMA2
// solid-folder decode); default is sequential decoding
var parallel = ReaderOptions.ForExternalStream.WithEnableParallelism(true);
2026-03-02 07:00:33 +00:00
// Extraction presets
var safeOptions = ExtractionOptions.SafeExtract; // No overwrite
var flatOptions = ExtractionOptions.FlatExtract; // No directory structure
2026-03-03 12:40:58 +00:00
var metadataOptions = ExtractionOptions.PreserveMetadata; // Keep timestamps and attributes
2026-02-10 11:10:04 +00:00
2026-06-11 17:24:42 +01:00
// Tune extraction copy buffering
2026-06-15 09:17:05 +01:00
var extractionOptions = new ExtractionOptions
{
BufferSize = 131072,
CheckCrc = true, // Default: validate entry checksums when archive metadata provides one
};
2026-06-11 17:24:42 +01:00
2026-02-10 10:48:42 +00:00
// Factory defaults:
// - file path / FileInfo overloads use LeaveStreamOpen = false
// - stream overloads use LeaveStreamOpen = true
2026-01-08 15:34:48 +00:00
```
2026-02-10 11:10:04 +00:00
Alternative: traditional object initializer:
```csharp
var options = new ReaderOptions
{
Password = "password",
LeaveStreamOpen = true,
2026-06-06 15:50:49 +01:00
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(932) },
ExtensionHint = "zip",
LookForHeader = true,
DisableCheckIncomplete = false,
BufferSize = 81920,
RewindableBufferSize = 1_048_576,
2026-08-02 18:08:51 +02:00
EnableParallelism = false,
2026-02-10 11:10:04 +00:00
};
2026-06-11 17:24:42 +01:00
var extractionOptions = new ExtractionOptions
{
ExtractFullPath = true,
Overwrite = true,
BufferSize = 131072,
};
2026-02-10 11:10:04 +00:00
```
2026-01-08 15:34:48 +00:00
### WriterOptions
2026-02-10 11:10:04 +00:00
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);
```
2026-06-06 15:50:49 +01:00
Use typed writer options when a format exposes extra settings:
2026-10-15 11:03:01 +01:00
`WriterFactory.OpenWriter` and `WriterFactory.OpenAsyncWriter` accept `ZipWriterOptions`
through `IWriterOptions` . `UseZip64` supports both seekable and non-seekable output;
non-seekable entries use 64-bit data descriptors, even when their final sizes are small.
Enable it before writing an entry whose compressed or uncompressed size may reach 4 GiB.
2026-06-06 15:50:49 +01:00
```csharp
// ZIP archive-level options
var zipWriterOptions = new ZipWriterOptions(CompressionType.Deflate)
{
ArchiveComment = "Created by SharpCompress",
UseZip64 = true,
CompressionLevel = 9,
};
// ZIP per-entry options
using (var writer = new ZipWriter(outputStream, zipWriterOptions))
using (var source = File.OpenRead("source.txt"))
{
writer.Write("entry.txt", source, new ZipWriterEntryOptions
{
CompressionType = CompressionType.ZStandard,
CompressionLevel = 3,
EntryComment = "per-entry comment",
ModificationDateTime = DateTime.UtcNow,
EnableZip64 = true,
});
}
// TAR-specific options
var tarOptions = new TarWriterOptions(CompressionType.GZip, finalizeArchiveOnClose: true)
{
HeaderFormat = TarHeaderWriteFormat.GNU_TAR_LONG_LINK,
};
// GZip-specific options
var gzipOptions = new GZipWriterOptions(compressionLevel: 9);
// 7z writing requires a seekable output stream and writes non-solid archives
var sevenZipOptions = new SevenZipWriterOptions(CompressionType.LZMA2)
{
CompressHeader = true,
LzmaProperties = new LzmaEncoderProperties(),
};
```
2026-02-10 11:10:04 +00:00
Alternative: traditional constructor with object initializer:
2026-01-08 15:34:48 +00:00
```csharp
var options = new WriterOptions(CompressionType.Deflate)
{
2026-02-10 11:10:04 +00:00
CompressionLevel = 9,
LeaveStreamOpen = true,
2026-01-08 15:34:48 +00:00
};
archive.SaveTo("output.zip", options);
```
2026-08-02 18:08:51 +02:00
`WriterOptions.EnableParallelism` (also available on `ZipWriterOptions` , `TarWriterOptions` , `GZipWriterOptions` , and `SevenZipWriterOptions` ) opts in to a format's optional parallel encode. No writer currently implements parallel encoding, so this is a no-op today; it is reserved for future use and mirrors `ReaderOptions.EnableParallelism` .
2026-02-10 10:48:42 +00:00
### Extraction behavior
2026-01-08 15:34:48 +00:00
2026-10-13 11:36:07 +01:00
`ZipArchiveEntry.OpenEntryStreamAsync` and `TarArchiveEntry.OpenEntryStreamAsync` are virtual and support newly added writable entries as well as entries read from an archive. Opening a new writable entry checks cancellation, rewinds its supplied stream, and returns a non-owning wrapper. Disposing that wrapper leaves the supplied stream open; archive disposal follows the entry's `closeStream` setting.
2026-01-08 15:34:48 +00:00
```csharp
2026-03-02 07:00:33 +00:00
var options = new ExtractionOptions
2026-01-08 15:34:48 +00:00
{
ExtractFullPath = true, // Recreate directory structure
Overwrite = true, // Overwrite existing files
2026-06-15 09:17:05 +01:00
PreserveFileTime = true, // Keep original timestamps
CheckCrc = true // Validate payload checksums when available
2026-01-08 15:34:48 +00:00
};
2026-02-10 10:48:42 +00:00
2026-03-02 07:00:33 +00:00
using (var archive = ZipArchive.OpenArchive("file.zip"))
2026-02-10 10:48:42 +00:00
{
2026-03-02 07:00:33 +00:00
archive.WriteToDirectory(@"C:\output", options);
2026-02-10 10:48:42 +00:00
}
```
2026-06-15 09:17:05 +01:00
`CheckCrc` validates archive-level payload checksums when the format stores reliable metadata, such as ZIP CRC32 values. Formats without payload checksums skip this validation. Decompressor integrity checks that are required to decode a stream may still fail even when `CheckCrc` is disabled.
2026-10-10 15:40:34 +01:00
WinZip AES authentication is always checked, including when `CheckCrc` is disabled. Complete or dispose entry streams to verify authentication; plaintext returned before completion must not be treated as authenticated. Invalid authentication tags throw `InvalidFormatException` , and missing ciphertext or tag bytes throw `IncompleteArchiveException` .
2026-10-10 15:40:33 +01:00
7z AES key derivation accepts iteration exponents 0 through 24 and the special `0x3F` direct-key mode. Larger iteration exponents throw `NotSupportedException` before key derivation, including when salt and IV are absent.
2026-08-05 13:44:19 +01:00
When using `SymbolicLinkHandler` , directory extraction rejects link targets outside the extraction root and never follows symbolic links or reparse points while extracting later entries. The handler itself remains trusted application code.
2026-02-10 10:48:42 +00:00
### Options matrix
```text
2026-03-02 07:00:33 +00:00
ReaderOptions: open-time behavior (password, encoding, stream ownership)
ExtractionOptions: extract-time behavior (overwrite, paths, timestamps, attributes, symlinks)
2026-02-10 10:48:42 +00:00
WriterOptions: write-time behavior (compression type/level, encoding, stream ownership)
ZipWriterEntryOptions: per-entry ZIP overrides (compression, level, timestamps, comments, zip64)
2026-01-08 15:34:48 +00:00
```
2026-02-10 15:51:50 +00:00
### Compression Providers
2026-06-07 11:20:34 +01:00
`ReaderOptions` and `WriterOptions` expose a `Providers` registry that controls which `ICompressionProvider` implementations are used for each `CompressionType` . The registry defaults to `CompressionProviderRegistry.Default` , so you only need to set it if you want to swap in a custom provider (for example the `SystemGZipCompressionProvider` or `SystemDeflateCompressionProvider` ). The selected registry is honored by Reader/Writer APIs, Archive APIs, and async entry-stream extraction paths.
2026-02-10 15:51:50 +00:00
```csharp
2026-06-07 11:20:34 +01:00
var registry = CompressionProviderRegistry.Default
.With(new SystemGZipCompressionProvider())
.With(new SystemDeflateCompressionProvider());
2026-03-03 12:40:58 +00:00
var readerOptions = ReaderOptions.ForFilePath.WithProviders(registry);
2026-02-10 15:51:50 +00:00
var writerOptions = new WriterOptions(CompressionType.GZip)
{
CompressionLevel = 6,
}.WithProviders(registry);
using var reader = ReaderFactory.OpenReader(input, readerOptions);
using var writer = WriterFactory.OpenWriter(output, ArchiveType.GZip, writerOptions);
```
2026-06-07 11:20:34 +01:00
Registry API summary:
```text
CompressionProviderRegistry.Default: built-in provider registry
CompressionProviderRegistry.Empty: empty registry, primarily useful for tests
With(provider): returns a new registry with that provider added or replaced
GetProvider(type): returns the registered ICompressionProvider, or null
CreateCompressStream(...): creates a compression stream or throws if unsupported
CreateDecompressStream(...): creates a decompression stream or throws if unsupported
CreateCompressStreamAsync(...): async stream creation counterpart
CreateDecompressStreamAsync(...): async stream creation counterpart
GetCompressingProvider(type): returns ICompressionProviderHooks when available
```
`ICompressionProvider` implementations declare their `CompressionType` , whether they support compression/decompression, and create sync/async streams. For simple providers, derive from `CompressionProviderBase` ; it supplies default async implementations that delegate to the synchronous methods. For read-only codecs, derive from `DecompressionOnlyProviderBase` .
```csharp
public sealed class CustomGZipProvider : CompressionProviderBase
{
public override CompressionType CompressionType => CompressionType.GZip;
public override bool SupportsCompression => true;
public override bool SupportsDecompression => true;
public override Stream CreateCompressStream(Stream destination, int compressionLevel) =>
new GZipStream(destination, CompressionMode.Compress, leaveOpen: false);
public override Stream CreateDecompressStream(Stream source) =>
new GZipStream(source, CompressionMode.Decompress, leaveOpen: false);
}
```
`CompressionContext` carries metadata that providers may need when creating streams, including `InputSize` , `OutputSize` , `Properties` , `CanSeek` , `FormatOptions` , and `ReaderOptions` . Use `CompressionContext.FromStream(stream)` to populate stream-derived values, `WithReaderOptions(...)` to attach reader metadata, and `ResolveArchiveEncoding()` to get the archive header encoding from the context.
2026-02-12 15:09:21 +00:00
When a format needs additional initialization/finalization data (LZMA, PPMd, etc.) the registry exposes `GetCompressingProvider` which returns the `ICompressionProviderHooks` contract; the rest of the API continues to flow through `Providers` , including pre/properties/post compression hook data.
2026-02-10 15:51:50 +00:00
2026-01-08 15:34:48 +00:00
---
## Compression Types
### Available Compressions
```csharp
// For creating archives
CompressionType.None // No compression (store)
2026-06-06 15:50:49 +01:00
CompressionType.GZip // GZip wrapper/combined tar compression
2026-01-08 15:34:48 +00:00
CompressionType.Deflate // DEFLATE (default for ZIP/GZip)
2026-01-12 16:08:16 +00:00
CompressionType.Deflate64 // Deflate64
2026-01-08 15:34:48 +00:00
CompressionType.BZip2 // BZip2
CompressionType.LZMA // LZMA (for 7Zip, LZip, XZ)
2026-06-06 15:50:49 +01:00
CompressionType.LZMA2 // LZMA2 (for 7Zip/XZ)
CompressionType.BCJ // 7Zip branch converter filter
CompressionType.BCJ2 // 7Zip branch converter filter
CompressionType.LZip // LZip wrapper/combined tar compression
CompressionType.Xz // XZ wrapper/combined tar compression
2026-01-08 15:34:48 +00:00
CompressionType.PPMd // PPMd (for ZIP)
CompressionType.Rar // RAR compression (read-only)
2026-06-06 15:50:49 +01:00
CompressionType.Lzw // LZW, including .Z/tar.Z reading
CompressionType.Shrink // ZIP shrink (read-only)
CompressionType.Reduce1 // ZIP reduce methods (read-only)
CompressionType.Reduce2
CompressionType.Reduce3
CompressionType.Reduce4
CompressionType.Explode // ZIP implode/explode (read-only)
CompressionType.Squeezed // ARC/ARJ legacy compression (read-only)
CompressionType.Packed // ARC legacy compression (read-only)
CompressionType.Crunched // ARC legacy compression (read-only)
CompressionType.Squashed // Legacy compression (read-only)
CompressionType.Crushed // Legacy compression (read-only)
CompressionType.Distilled // Legacy compression (read-only)
2026-01-12 16:08:16 +00:00
CompressionType.ZStandard // ZStandard
2026-06-06 15:50:49 +01:00
CompressionType.ArjLZ77 // ARJ compression (read-only)
CompressionType.AceLZ77 // ACE compression (read-only)
CompressionType.Unknown
2026-01-12 16:08:16 +00:00
// For Tar archives with compression
// Use WriterFactory to create compressed tar archives
2026-01-15 13:29:57 +00:00
using (var writer = WriterFactory.OpenWriter(stream, ArchiveType.Tar, CompressionType.GZip)) // Tar.GZip
using (var writer = WriterFactory.OpenWriter(stream, ArchiveType.Tar, CompressionType.BZip2)) // Tar.BZip2
2026-01-08 15:34:48 +00:00
```
### Archive Types
```csharp
ArchiveType.Zip
ArchiveType.Tar
ArchiveType.GZip
ArchiveType.Rar
ArchiveType.SevenZip
2026-06-06 15:50:49 +01:00
ArchiveType.Arc
ArchiveType.Arj
ArchiveType.Ace
ArchiveType.Lzw
2026-01-08 15:34:48 +00:00
```
---
## Patterns & Examples
### Extract with Error Handling
```csharp
try
{
2026-04-10 17:47:33 +01:00
using (var archive = ZipArchive.OpenArchive("archive.zip",
2026-02-10 11:10:04 +00:00
ReaderOptions.ForEncryptedArchive("password")))
2026-01-08 15:34:48 +00:00
{
2026-02-10 10:48:42 +00:00
archive.WriteToDirectory(@"C:\output");
2026-01-08 15:34:48 +00:00
}
}
2026-09-22 01:40:55 +01:00
catch (CryptographicException)
2026-01-08 15:34:48 +00:00
{
Console.WriteLine("Password required");
}
2026-09-22 01:40:55 +01:00
catch (ArchiveException)
2026-01-08 15:34:48 +00:00
{
Console.WriteLine("Archive is invalid");
}
catch (SharpCompressException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
```
### Extract with Progress
```csharp
var progress = new Progress<ProgressReport>(report =>
{
Console.WriteLine($"Extracting {report.EntryPath}: {report.PercentComplete}%");
});
2026-03-03 12:40:58 +00:00
var options = ReaderOptions.ForFilePath.WithProgress(progress);
2026-01-15 13:29:57 +00:00
using (var archive = ZipArchive.OpenArchive("archive.zip", options))
2026-01-08 15:34:48 +00:00
{
archive.WriteToDirectory(@"C:\output");
}
```
### Async Extract with Cancellation
2026-10-13 12:57:14 +01:00
Async archive and reader/writer operations dispose SharpCompress resources asynchronously on every target, including .NET Framework 4.8 and .NET Standard 2.0. `SharpCompressStream.DisposeAsync()` and `ZlibStream.DisposeAsync()` are available on every target; stream wrappers forward disposal to runtime `IAsyncDisposable` implementations where available, falling back to synchronous disposal only for streams that do not support it.
2026-01-08 15:34:48 +00:00
```csharp
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromMinutes(5));
try
{
2026-02-12 10:32:20 +00:00
await using (var archive = await ZipArchive.OpenAsyncArchive("archive.zip"))
2026-01-08 15:34:48 +00:00
{
2026-01-12 16:08:16 +00:00
await archive.WriteToDirectoryAsync(
@"C:\output",
cancellationToken: cts.Token
);
2026-01-08 15:34:48 +00:00
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Extraction cancelled");
}
```
### Create with Custom Compression
```csharp
2026-01-15 13:04:09 +00:00
using (var archive = ZipArchive.CreateArchive())
2026-01-08 15:34:48 +00:00
{
archive.AddAllFromDirectory(@"D:\source");
// Fastest
2026-01-15 13:04:09 +00:00
archive.SaveTo("fast.zip", new WriterOptions(CompressionType.Deflate)
{
CompressionLevel = 1
2026-01-08 15:34:48 +00:00
});
// Balanced (default)
archive.SaveTo("normal.zip", CompressionType.Deflate);
// Best compression
2026-01-15 13:04:09 +00:00
archive.SaveTo("best.zip", new WriterOptions(CompressionType.Deflate)
{
CompressionLevel = 9
2026-01-08 15:34:48 +00:00
});
}
```
### Stream Processing (No File I/O)
```csharp
using (var outputStream = new MemoryStream())
2026-01-15 13:04:09 +00:00
using (var archive = ZipArchive.CreateArchive())
2026-01-08 15:34:48 +00:00
{
// Add content from memory
using (var contentStream = new MemoryStream(Encoding.UTF8.GetBytes("Hello")))
{
archive.AddEntry("file.txt", contentStream);
}
// Save to memory
archive.SaveTo(outputStream, CompressionType.Deflate);
// Get bytes
byte[] archiveBytes = outputStream.ToArray();
}
```
2026-02-14 10:26:33 +00:00
### Buffered Forward-Only Streams
`SharpCompressStream` can wrap streams with buffering for forward-only scenarios:
```csharp
// Wrap a non-seekable stream with buffering
using (var bufferedStream = new SharpCompressStream(rawStream))
{
// Provides ring buffer functionality for reading ahead
// and seeking within buffered data
using (var reader = ReaderFactory.OpenReader(bufferedStream))
{
while (reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(@"C:\output");
}
}
}
```
Useful for:
- Non-seekable streams (network streams, pipes)
- Forward-only reading with limited look-ahead
- Buffering unbuffered streams for better performance
2026-01-08 15:34:48 +00:00
### Extract Specific Files
```csharp
2026-01-15 13:29:57 +00:00
using (var archive = ZipArchive.OpenArchive("archive.zip"))
2026-01-08 15:34:48 +00:00
{
var filesToExtract = new[] { "file1.txt", "file2.txt" };
foreach (var entry in archive.Entries.Where(e => filesToExtract.Contains(e.Key)))
{
entry.WriteToFile(@"C:\output\" + entry.Key);
}
}
```
### List Archive Contents
```csharp
2026-01-15 13:29:57 +00:00
using (var archive = ZipArchive.OpenArchive("archive.zip"))
2026-01-08 15:34:48 +00:00
{
foreach (var entry in archive.Entries)
{
if (entry.IsDirectory)
Console.WriteLine($"[DIR] {entry.Key}");
else
Console.WriteLine($"[FILE] {entry.Key} ({entry.Size} bytes)");
}
}
```
---
## Common Mistakes
### ✗ Wrong - Stream not disposed
```csharp
var stream = File.OpenRead("archive.zip");
2026-01-15 13:29:57 +00:00
var archive = ZipArchive.OpenArchive(stream);
2026-01-08 15:34:48 +00:00
archive.WriteToDirectory(@"C:\output");
// stream not disposed - leaked resource
```
### ✓ Correct - Using blocks
```csharp
using (var stream = File.OpenRead("archive.zip"))
2026-01-15 13:29:57 +00:00
using (var archive = ZipArchive.OpenArchive(stream))
2026-01-08 15:34:48 +00:00
{
archive.WriteToDirectory(@"C:\output");
}
// Both properly disposed
```
### ✗ Wrong - Mixing API styles
```csharp
// Loading entire archive then iterating
2026-01-15 13:29:57 +00:00
using (var archive = ZipArchive.OpenArchive("large.zip"))
2026-01-08 15:34:48 +00:00
{
var entries = archive.Entries.ToList(); // Loads all in memory
foreach (var e in entries)
{
e.WriteToFile(...); // Then extracts each
}
}
```
### ✓ Correct - Use Reader for large files
```csharp
// Streaming iteration
using (var stream = File.OpenRead("large.zip"))
2026-01-15 13:29:57 +00:00
using (var reader = ReaderFactory.OpenReader(stream))
2026-01-08 15:34:48 +00:00
{
while (reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(@"C:\output");
}
}
```
---
2026-10-13 09:57:19 +01:00
## CRC-Checking Stream Lifetime
2026-10-13 10:26:09 +01:00
`SharpCompressStream` rejects reading and starting recording after disposal. Its pooled ring buffer is released even when disposal of the underlying stream fails.
2026-10-13 10:29:07 +01:00
`LzmaStream` also rejects reads and writes after disposal. Failed initialization releases internal buffers without closing the supplied stream; successful construction retains the specified `leaveOpen` semantics. Disposal releases internal buffers even if finalization or underlying stream disposal throws.
2026-10-13 09:57:19 +01:00
`SharpCompress.Compressors.LZMA.Utilities.CrcCheckStream` validates its expected CRC on disposal. A mismatch throws `ArchiveOperationException` , but pooled buffers are still released. Repeated disposal is safe, including after failed CRC validation. Once disposed, `CanWrite` is `false` , and `Write` / `WriteAsync` throw `ObjectDisposedException` .
2026-01-08 15:34:48 +00:00
## Related Documentation
- [USAGE.md ](USAGE.md ) - Complete code examples
- [FORMATS.md ](FORMATS.md ) - Supported formats
- [PERFORMANCE.md ](PERFORMANCE.md ) - API selection guide
2026-10-12 17:10:32 +01:00
2026-10-19 14:43:51 +01:00
## 7z Decoder Lifetime
Both `Dispose()` and `DisposeAsync()` release a 7z archive's cached folder
decoder, including after partially reading an entry. Temporary encoded-header
decoders are released after parsing or validation failure. Decoder cleanup
returns pooled input and dictionary buffers without closing a borrowed archive
source; the archive's `LeaveStreamOpen` setting still controls source ownership.
For solid archives, prefer `ExtractAllEntries()` / `ExtractAllEntriesAsync()` to
reuse the folder decoder across entries. A reader borrowed from an archive can
be disposed without closing that archive's source.
2026-10-22 08:22:48 +01:00
The entries of a solid folder share one forward-only decoder. Reading only part
of an entry does not corrupt the entries that follow: the decoder skips forward
over the bytes that were not read when the next entry is opened. Read an entry
before opening the next entry of the same folder - the shared decoder cannot
serve two open entry streams of the same folder at the same time. Mixing
2026-10-22 09:11:14 +01:00
synchronous and asynchronous entry APIs restarts the folder decoder when needed;
same-mode sequential access reuses it. Failed decoder reads also invalidate reuse.
2026-10-22 08:22:48 +01:00
2026-10-12 15:29:40 +01:00
## 7z Encrypted Decoding Errors
AES-encrypted 7z codec data errors and encrypted-header CRC failures throw `SharpCompress.Common.CryptographicException` ,
with the original decoder error in `InnerException` . The exception can indicate either an
incorrect password or corrupt encrypted data; 7z AES has no independent password verifier.
`CryptographicException(string message, Exception inner)` preserves an underlying failure.
Unencrypted codec errors retain their existing behavior. This does not guarantee detection
of every incorrect password, particularly for data without compression or integrity checking.
2026-10-12 17:10:32 +01:00
2026-10-12 15:29:40 +01:00
## 7z Encryption Detection
For 7z archives, `IsEncrypted` is true when any entry has an AES-encrypted data stream.
Streamless empty files and directories are not encrypted. Archives without files return false.