StreamLZ 1.2.0
See the version list below for details.
dotnet add package StreamLZ --version 1.2.0
NuGet\Install-Package StreamLZ -Version 1.2.0
<PackageReference Include="StreamLZ" Version="1.2.0" />
<PackageVersion Include="StreamLZ" Version="1.2.0" />
<PackageReference Include="StreamLZ" />
paket add StreamLZ --version 1.2.0
#r "nuget: StreamLZ, 1.2.0"
#:package StreamLZ@1.2.0
#addin nuget:?package=StreamLZ&version=1.2.0
#tool nuget:?package=StreamLZ&version=1.2.0
StreamLZ
High-performance LZ compression library for .NET with streaming support.
Features
- Up to 10.7 GB/s decompress (level 6, silesia), down to 27% ratio (level 11, enwik8)
- Simple level scale (1-11) — higher = better ratio, slower
- Streaming — SLZ1 frame format supports files of any size
- Sliding window — cross-block match references for better ratio
- Parallel compress and decompress — automatic multi-threading at L6+ (see Threading Model)
- Async —
CompressFileAsync,DecompressFileAsync,IAsyncDisposableonSlzStream - Validation —
TryDecompress(non-throwing),IsValidFrame, content checksums - Zero allocations on the hot path (pooled scratch buffers)
- Native AOT and trimming compatible
- Targets net8.0 and net10.0
Installation
dotnet add package StreamLZ
Quick Start
using StreamLZ;
// Simplest: compress and decompress byte arrays (SLZ1 framed, self-describing)
byte[] compressed = Slz.CompressFramed(data);
byte[] restored = Slz.DecompressFramed(compressed); // no size tracking needed
// Compress / decompress files
Slz.CompressFile("input.txt", "output.slz");
Slz.DecompressFile("output.slz", "restored.txt");
// Stream-based (any size)
Slz.CompressStream(input, output, level: 6);
// Named compression levels
byte[] fast = Slz.CompressFramed(data, SlzCompressionLevel.Fast);
byte[] max = Slz.CompressFramed(data, SlzCompressionLevel.Maximum);
Compression Levels
| Level | Compress | Decompress | Ratio (enwik8) | Parallel Compress | Parallel Decompress |
|---|---|---|---|---|---|
| 1 | 287 MB/s | 5.4 GB/s | 58.6% | ||
| 2 | 243 MB/s | 5.4 GB/s | 56.9% | ||
| 3 | 225 MB/s | 5.3 GB/s | 56.5% | ||
| 4 | 231 MB/s | 4.4 GB/s | 54.0% | ||
| 5 | 58 MB/s | 4.6 GB/s | 42.2% | ||
| 6 | 56 MB/s | 5.7 GB/s | 33.7% | ✅ | ✅ |
| 7 | 39 MB/s | 5.8 GB/s | 33.6% | ✅ | ✅ |
| 8 | 32 MB/s | 5.6 GB/s | 33.7% | ✅ | ✅ |
| 9 | 6.0 MB/s | 1.3 GB/s | 27.4% | partial | |
| 10 | 5.8 MB/s | 1.3 GB/s | 27.2% | partial | |
| 11 | 5.5 MB/s | 1.3 GB/s | 27.2% | partial |
See Threading Model below for details on how parallelism works at each level.
API
StreamLZ offers three API tiers. Choose based on your use case:
Framed in-memory (simplest — self-describing round-trip)
Uses the SLZ1 frame format. Output includes size metadata so decompression needs no external information. Best for storing/transmitting compressed blobs.
byte[] compressed = Slz.CompressFramed(data);
byte[] restored = Slz.DecompressFramed(compressed);
// Named levels for readability
byte[] fast = Slz.CompressFramed(data, SlzCompressionLevel.Fast);
Raw in-memory (zero-copy — caller manages buffers)
No framing. Caller must track the original size and provide output buffers
(including Slz.SafeSpace extra bytes for decompression). Best for hot paths
where you control the buffer lifecycle.
int bound = Slz.GetCompressBound(data.Length);
byte[] dst = new byte[bound];
int compSize = Slz.Compress(data, dst, level: 3);
byte[] output = new byte[originalSize + Slz.SafeSpace];
Slz.Decompress(compressed, output, originalSize);
// Non-throwing variant for untrusted data
if (Slz.TryDecompress(compressed, output, originalSize, out int written))
// success
Important: Raw and framed formats are not interchangeable. Data compressed
with Compress must be decompressed with Decompress (not DecompressFramed),
and vice versa.
File and stream (any size, SLZ1 framed)
Uses the SLZ1 frame format with a sliding window for cross-block match references. Supports files of any size with bounded memory usage.
// Sync
Slz.CompressFile("input.txt", "output.slz");
Slz.DecompressFile("output.slz", "restored.txt");
Slz.CompressStream(input, output, level: 6);
Slz.DecompressStream(input, output);
// Async
await Slz.CompressFileAsync("input.txt", "output.slz", cancellationToken: ct);
await Slz.DecompressFileAsync("output.slz", "restored.txt", cancellationToken: ct);
// With content checksum for integrity verification
Slz.CompressFile("input.txt", "output.slz", useContentChecksum: true);
// Limit compression threads (for server workloads)
Slz.CompressFile("input.txt", "output.slz", maxThreads: 4);
SlzStream (GZipStream-style wrapper)
// Compress (supports await using for async disposal)
await using var compressStream = new SlzStream(outputStream, CompressionMode.Compress);
inputStream.CopyTo(compressStream);
// Decompress
await using var decompressStream = new SlzStream(inputStream, CompressionMode.Decompress);
decompressStream.CopyTo(outputStream);
// With options
var options = new SlzStreamOptions
{
Level = 9,
UseContentChecksum = true,
LeaveOpen = true
};
await using var stream = new SlzStream(inner, CompressionMode.Compress, options);
Note: Disposing an SlzStream in compress mode without writing any data produces
no output. To get a valid empty SLZ1 stream, write at least one byte, or use
CompressFramed(ReadOnlySpan<byte>.Empty).
Validation
bool valid = Slz.IsValidFrame(compressedData);
bool valid = Slz.IsValidFrame(stream); // rewinds if seekable
JIT warmup (optional)
// Called automatically on first use of Slz. Call explicitly at app
// startup to move the ~15ms JIT cost to a predictable point.
Slz.WarmUp();
Comparison vs LZ4, Snappy, Zstd
enwik8 (100 MB text, 3-run median)
| Compressor | Ratio | Compress | Decompress | Parallel Compress | Parallel Decompress |
|---|---|---|---|---|---|
| Snappy | 56.7% | 518 MB/s | 1,177 MB/s | ||
| LZ4 Fast | 57.3% | 484 MB/s | 4,335 MB/s | ||
| SLZ L1 | 58.6% | 288 MB/s | 5,421 MB/s | ||
| Zstd 1 | 40.7% | 422 MB/s | 1,072 MB/s | ||
| LZ4 Max | 41.9% | 23 MB/s | 4,335 MB/s | ||
| SLZ L5 | 42.2% | 59 MB/s | 4,402 MB/s | ||
| Zstd 3 | 35.5% | 282 MB/s | 1,289 MB/s | ||
| SLZ L6 | 33.7% | 55 MB/s | 5,470 MB/s | ✅ | ✅ |
| Zstd 9 | 31.1% | 65 MB/s | 1,223 MB/s | ||
| Zstd 19 | 26.9% | 2.1 MB/s | 926 MB/s | ||
| SLZ L11 | 27.3% | 5.5 MB/s | 1,339 MB/s | partial |
silesia (212 MB mixed, 3-run median)
| Compressor | Ratio | Compress | Decompress | Parallel Compress | Parallel Decompress |
|---|---|---|---|---|---|
| Snappy | 48.1% | 763 MB/s | 1,573 MB/s | ||
| LZ4 Fast | 47.4% | 717 MB/s | 4,510 MB/s | ||
| SLZ L1 | 47.1% | 421 MB/s | 5,858 MB/s | ||
| Zstd 1 | 34.5% | 561 MB/s | 1,074 MB/s | ||
| LZ4 Max | 36.3% | 17 MB/s | 4,832 MB/s | ||
| SLZ L5 | 36.4% | 79 MB/s | 5,222 MB/s | ||
| SLZ L6 | 28.2% | 73 MB/s | 10,817 MB/s | ✅ | ✅ |
| Zstd 9 | 27.9% | 88 MB/s | 1,121 MB/s | ||
| SLZ L11 | 24.7% | 7.5 MB/s | 1,370 MB/s | partial |
All benchmarks on Intel Arrow Lake-S (Ultra 9 285K), 24-core, .NET 10.
Threading Model
StreamLZ uses different threading strategies depending on the compression level:
L1-L5 (Fast codec): Single-threaded compress and decompress. The high decompress throughput (5+ GB/s) comes from the simple token format, not parallelism.
L6-L8 (High codec, self-contained): Fully parallel. Each 256KB chunk is compressed and decompressed independently across all available cores. This is why L6 decompresses at 5.3 GB/s despite using a more complex codec than L1.
L9-L11 (High codec, sliding window): Compression is single-threaded because chunks reference previous output via a sliding window. Decompression uses a batched two-phase approach that processes chunks in batches of
ProcessorCount(e.g. 24 on a 24-core machine). For each batch:- Phase 1 (parallel):
ReadLzTableruns on all chunks in the batch simultaneously — this decodes the entropy streams (Huffman/tANS) and unpacks offsets, which is the most CPU-intensive part. - Phase 2 (serial):
ProcessLzRunsresolves tokens and copies literals/matches for each chunk in order, since match copies can reference output from earlier chunks.
Then the next batch starts. This yields ~47% faster decompression than fully serial on a 24-core machine.
- Phase 1 (parallel):
Compression thread count can be limited with the maxThreads parameter (e.g. for server workloads). Decompression threading is automatic and cannot be disabled.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- System.IO.Hashing (>= 9.0.4)
-
net8.0
- System.IO.Hashing (>= 9.0.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.4.4 | 76 | 4/12/2026 |
| 1.4.3 | 66 | 4/10/2026 |
| 1.4.2 | 58 | 4/10/2026 |
| 1.4.1 | 66 | 4/10/2026 |
| 1.4.0 | 67 | 4/7/2026 |
| 1.3.0 | 57 | 4/7/2026 |
| 1.2.1 | 67 | 4/6/2026 |
| 1.2.0 | 69 | 4/6/2026 |
| 1.1.0 | 69 | 4/6/2026 |
| 1.0.9 | 69 | 3/31/2026 |
| 1.0.8 | 62 | 3/30/2026 |
| 1.0.7 | 53 | 3/30/2026 |
| 1.0.6 | 66 | 3/30/2026 |
| 1.0.5 | 60 | 3/30/2026 |
| 1.0.4 | 66 | 3/29/2026 |
| 1.0.3 | 59 | 3/29/2026 |
| 1.0.2 | 60 | 3/29/2026 |
| 1.0.1 | 70 | 3/27/2026 |
| 1.0.0 | 71 | 3/27/2026 |