Create a reusable `SharpCompressClient`, or constructor-inject `ISharpCompressClient` and the workflow interfaces from `SharpCompress.Archives`. Consumers can use any DI container or ordinary constructors; Pure.DI only generates SharpCompress's internal service wiring.
```csharp
using System.IO;
using SharpCompress;
using SharpCompress.Common;
using SharpCompress.Factories;
using SharpCompress.Providers;
using SharpCompress.Providers.System;
using SharpCompress.Writers;
var providers = CompressionProviderRegistry.Default
.With(new SystemDeflateCompressionProvider());
var client = new SharpCompressClient(
new SharpCompressConfiguration(providers: providers));
Directory.CreateDirectory("output");
await using (var archive = await client.OpenAsyncArchive(
// Limit one client to ZIP. Other clients and convenience factories are unaffected.
var zipOnly = new SharpCompressClient(new SharpCompressConfiguration(
new FormatRegistry([new ZipFactory()], [])));
```
Client configuration and registries are immutable. Per-operation options override client provider defaults only when `Providers` is explicitly assigned (including explicitly selecting the built-in default). Options passed by the caller are not mutated. Factories and providers shared by a client must be thread-safe; opened archives/readers/writers and their streams are independent, caller-disposed objects.
`client.Inspector` preserves caller stream positions during detection and inspection. `client.Extractor` handles solid archives sequentially and keeps supplied destination streams open. Filesystem writing normalizes entry names relative to the source directory. See the [instance API reference](API.md#instance-services), including [migration from global registration](API.md#migrating-to-instance-services).
SharpCompress now provides full async/await support for all I/O operations. All `Read`, `Write`, and extraction operations have async equivalents ending in `Async` that accept an optional `CancellationToken`. This enables better performance and scalability for I/O-bound operations.
When dealing with Streams, the rule should be that you don't close a stream you didn't create. This, in effect, should mean you should always put a Stream in a using block to dispose it.
In this example, reader should get disposed. However, stream rules should say the the `FileStream` created by `File.Open` should remain open. However, the .NET Framework closes it for you by default unless you override the constructor. In general, you should be writing Stream code like this:
To be explicit though, consider always using the overloads that use `ReaderOptions` or `WriterOptions` and explicitly set `LeaveStreamOpen` the way you want.
If using Compression Stream classes directly and you don't want the wrapped stream to be closed. Use the `NonDisposingStream` as a wrapper to prevent the stream being disposed. The change in 0.21 simplified a lot even though the usage is a bit more convoluted.
`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.
For optimal performance with solid Rar and 7Zip archives, extract entries sequentially. `WriteToDirectory` handles that internally for simple extraction. Use `ExtractAllEntries` when you need to manually iterate in sequential order.
`DetectArchive` does not enumerate entries. It reports both Archive and Reader API availability; reader-only formats include Ace, Arc, Arj, standalone LZW, and compressed TAR wrappers.
### Inspect archive metadata
```C#
var information = ArchiveFactory.InspectArchive(archivePath);
`InspectArchive` parses archive metadata, which can require a complete sequential scan for TAR and compressed TAR files. It returns partial information for encrypted headers without a password or missing archive parts; inspect `Status` and `Limitations` before using nullable metadata values.
Use `information.Detection` for format identification when inspecting an archive; calling `DetectArchive` first adds an unnecessary probe. Nullable metadata can still be absent when `Status` is `Complete`. `EntriesWithUnknownSizeCount` describes sizes unavailable to a forward-only reader before entry data, rather than sizes unavailable to the completed inspection.
By default `ReaderOptions` and `WriterOptions` already include `CompressionProviderRegistry.Default` via their `Providers` property, so you can read and write without touching the registry yet still get SharpCompress’s built-in implementations.
The configured registry is used consistently across Reader APIs, Writer APIs, Archive APIs, and async entry-stream extraction, including compressed TAR wrappers and ZIP async decompression.
To replace specific algorithms (for example to use `System.IO.Compression` for GZip or Deflate), create a modified registry and pass it through the same options:
The registry is immutable. `With(provider)` returns a new registry and replaces any existing provider for that provider's `CompressionType`. You can inspect or use providers directly with `GetProvider`, `CreateCompressStream`, `CreateDecompressStream`, and their async/context overloads, but most application code should flow the registry through `ReaderOptions` or `WriterOptions` so archive readers and writers can supply the right `CompressionContext`.
To implement a custom provider, implement `ICompressionProvider` directly or derive from `CompressionProviderBase` for default async methods. Derive from `DecompressionOnlyProviderBase` for read-only codecs. Providers can use `CompressionContext` for stream size, seekability, reader options, compression properties, and format-specific metadata.
The registry also exposes `GetCompressingProvider` (now returning `ICompressionProviderHooks`) when a compression format needs pre- or post-stream data (e.g., LZMA/PPMd). Implementations that need extra headers can supply those bytes through the `ICompressionProviderHooks` members while the rest of the API still works through the `Providers` property.
using Stream archiveStream = File.OpenWrite("output.zip");
await using var writer = await WriterFactory.OpenAsyncWriter(archiveStream, ArchiveType.Zip, new WriterOptions(CompressionType.Deflate), cancellationToken);
using Stream fileStream = File.OpenRead("input.txt");