A fully managed, performant and modern C# (.NET Standard 1.3 compatible) implementation of the zlib compression library which provides in-memory compression, decompression, and integrity checks of uncompressed data in the zlib (RFC (Request for Comments) 1950) and raw deflate (RFC 1951) data formats (but not the gzip or zip formats).
If you simply want to compress or decompress data in the zlib format in a .NET application, there is a ZLibStream
class for doing this in .NET 6 and later versions:
byte[] inputData = Encoding.ASCII.GetBytes("hello, hello!");
// Compress
using MemoryStream memoryStream = new();
using (ZLibStream deflateStream = new(memoryStream, CompressionMode.Compress, true))
deflateStream.Write(inputData, 0, inputData.Length);
byte[] compressedData = memoryStream.ToArray();
// Uncompress
byte[] uncompressedData = new byte[inputData.Length];
memoryStream.Seek(0, SeekOrigin.Begin);
using (ZLibStream inflateStream = new(memoryStream, CompressionMode.Decompress))
inflateStream.Read(uncompressedData, 0, uncompressedData.Length);
Debug.Assert(Enumerable.SequenceEqual(inputData, uncompressedData));
In earlier versions of .NET, there are the DeflateStream
and InflateStream
classes that can be used to compress and decompress data in the raw deflate (RFC 1951) format.
Besides being unsupported in .NET 5 and earlier versions, the ZLibStream
class also doesn't provide any functionality to retrieve information such as the total number of bytes processed and output, or the Adler-32 checksum of the data.
There are indeed other third-party and fully managed C#/.NET libraries that already provide this functionality but ZLibDotNet was implemented during the porting of a C/C++ library to C#/.NET where it was undesirable to rely on any existing third-party software. It has been designed to provide an API surface that is very similar to the one that the original ported C library provides and also adds support for Span<byte>
buffers.
ZLibDotNet is preferably installed using NuGet:
PM> Install-Package ZLibDotNet
Below is an example of how to compress and uncompress some sample data using the ZLib
and ZStream
types in the ZLibDotNet
namespace:
using static ZLibDotNet.ZLib;
using ZLibDotNet;
ReadOnlySpan<byte> inputData = Encoding.ASCII.GetBytes("hello, hello!");
// Compress
ZLib zlib = new();
uint sourceLen = zlib.CompressBound((uint)s_inputData.Length);
Span<byte> compressedData = new byte[sourceLen];
ZStream zStream = new()
{
Input = inputData,
Output = compressedData
};
_ = zlib.DeflateInit(ref zStream, Z_DEFAULT_COMPRESSION);
_ = zlib.Deflate(ref zStream, Z_FULL_FLUSH);
_ = zlib.DeflateEnd(ref zStream);
// Uncompress
Span<byte> uncomressedData = new byte[inputData.Length];
zStream.Input = compressedData;
zStream.Output = uncomressedData;
_ = zlib.InflateInit(ref zStream);
_ = zlib.Inflate(ref zStream, Z_SYNC_FLUSH);
Debug.Assert(MemoryExtensions.SequenceEqual(inputData, uncomressedData));
Check out the unit tests for more examples.
ZStream
has been named after the equivalent z_stream
type in the ported library. It intentionally breaks the CA1711 naming rule as it's not a System.IO.Stream
but a ref struct
.
Input
is a ReadOnlySpan<byte>
property that defines the input buffer of the data to be compressed or uncompressed. The optional int
properties NextIn
and AvailableIn
can be used to specify a starting position in the buffer and the maximum number of bytes to consume from it respectively.
Similarly, there is a Span<Byte>
property named Output
for the output buffer with corresponding NextOut
and AvailableOut
properties.
Using the NextIn
/NextOut
and AvailableIn
/AvailableOut
properties is not required and can be avoided by slicing the input and output buffers.
The software is provided 'as-is', without any kind of express or implied warranty whatsoever. See the license file for details.
Since the implementation of ZLibDotNet is heavily based on the C implementation of the ported zlib data compression library, any questions that are not directly related to the C#/.NET implementation in this repository are referred to the authors of the original zlib library. There is a documentation with frequently asked questions, a manual and an email address available at https://zlib.net.
If you any questions or feedback about the managed code in this repository, please open an issue.
Contributions such as bug fixes, extended functionality within the scope of the zlib compression library and other kind of improvements are welcome.
Follow these steps when contributing code to this repository.
Below is an exhaustive list of the functions and macros in the zlib compression library that have currently been ported, and their C#/.NET counterparts.
C function/macro | C# API(s) |
---|---|
int deflateInit(z_streamp strm, int level) |
int DeflateInit(ref ZStream strm, int level) |
int deflateInit2(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy) |
int DeflateInit(ref ZStream strm, int level, int method, int windowBits, int memLevel, int strategy) |
int deflate(z_streamp strm, int flush) |
int Deflate(ref ZStream strm, int flush) |
int deflateEnd (z_streamp strm) |
int DeflateEnd(ref ZStream strm) |
int inflateInit (z_streamp strm) |
int InflateInit(ref ZStream strm) |
int inflateInit2 (z_streamp strm, int windowBits) |
int InflateInit(ref ZStream strm, int windowBits) |
int inflate (z_streamp strm, int flush) |
int Inflate(ref ZStream strm, int flush) |
int inflateEnd (z_streamp strm) |
int InflateEnd(ref ZStream strm) |
int deflateSetDictionary (z_streamp strm, const Bytef* dictionary, uInt dictLength) |
int DeflateSetDictionary(ref ZStream strm, byte[] dictionary, int dictLength) int DeflateSetDictionary(ref ZStream strm, byte[] dictionary) int DeflateSetDictionary(ref ZStream strm, ReadOnlySpan<byte> dictionary) |
int deflateParams (z_streamp strm, int level, int strategy) |
int DeflateParams(ref ZStream strm, int level, int strategy) |
int inflateSetDictionary (z_streamp strm, const Bytef* dictionary, uInt dictLength) |
int InflateSetDictionary(ref ZStream strm, byte[] dictionary, int dictLength) int InflateSetDictionary(ref ZStream strm, byte[] dictionary) int InflateSetDictionary(ref ZStream strm, ReadOnlySpan<byte> dictionary) |
int inflateSync (z_streamp strm) |
int InflateSync(ref ZStream strm) |
int inflateCopy (z_streamp dest, z_streamp source) |
int InflateCopy(ref ZStream source, ref ZStream dest) |
int inflateReset (z_streamp strm) |
int InflateReset(ref ZStream strm) |
int inflateReset2 (z_streamp strm, int windowBits) |
int InflateReset(ref ZStream strm, int windowBits) |
int inflatePrime (z_streamp strm, int bits, int value) |
int InflatePrime (ref ZStream strm, int bits, int value) |
int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) |
int Compress(byte[] dest, out int destLen, byte[] source, int sourceLen) int Compress(Span<byte> dest, out int destLen, ReadOnlySpan<byte> source) |
int compress2 (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level) |
int Compress(byte[] dest, out int destLen, byte[] source, int sourceLen, int level) int Compress(Span<byte> dest, out int destLen, ReadOnlySpan<byte> source, int level) |
uLong compressBound (uLong sourceLen) |
uint CompressBound(uint sourceLen) |
int uncompress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) |
int Uncompress(byte[] dest, out int destLen, byte[] source, int sourceLen) int Uncompress(Span<byte> dest, out int destLen, ReadOnlySpan<byte> source) |
int uncompress2 (Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen) |
int Uncompress(byte[] dest, out int destLen, byte[] source, out int sourceLen) int Uncompress(Span<byte> dest, out int destLen, ReadOnlySpan<byte> source, out int sourceLen) |
uLong adler32 (uLong adler, const Bytef *buf, uInt len) |
uint Adler32(uint adler, byte[] buf, int len) uint Adler32(uint adler, ReadOnlySpan<byte> buf) |