EasyCompressor

NuGet NuGet License: MIT Build Status

EasyCompressor

An Easy-to-Use and Optimized compression library for .NET that unified several compression algorithms including LZ4, Snappy, Zstd, LZMA, Brotli, GZip, ZLib, and Deflate.

Along with a great Performance Benchmark between different compression algorithms.

This library aids in Improving Performance by Reducing Memory Usage and Bandwidth Usage. (see How)

Usage

Features

Note

The default comparison levels are carefully configured based on extensive benchmarking to ensure the highest level of efficiency and speed at a reasonable compression ratio.

Improving Data Transfer Speed by Sending/Receiving Less

Compression/Decompression has overhead but it reduces the size of your data, which can potentially result in faster transfer times, even when accounting for the additional time required for compression and decompression.

When a file is compressed, it becomes smaller in size, which means it requires less bandwidth to transfer. If the compression ratio is significant, the reduced file size can compensate for the extra time needed for compression and decompression.

For example, let’s say you have an uncompressed file that takes 10 seconds to transfer. If you compress this file using a fast compressor like LZ4, Snappy, or Zstd, the compression time might be around 1 second. However, the compressed file size is significantly smaller, let’s say it’s only 20% of the original size. Now, when you transfer the compressed file, it will only take 2 seconds (20% of the original transfer time). In this scenario, the total time (compression time + transfer time) would be 3 seconds (1 second for compression + 2 seconds for transfer), which is less than the original 10 seconds it would have taken to transfer the uncompressed file.

It’s important to note that the actual time savings will depend on various factors, such as the compression ratio achieved, the speed of the compression and decompression algorithms, the network bandwidth, and other system-specific considerations. However, with fast compressors like LZ4, Snappy, or Zstd and significant compression ratios, it is possible to achieve overall time savings when transferring compressed files compared to transferring uncompressed files.

Nuget Packages

Package Description
EasyCompressor Including Algorithms :
- Brotli (Highest compression ratio - the Smallest size) (Only available in .NETCoreApp2.1, .NETStandard2.1 and above)
- GZip
- Deflate
- ZLib (Only available in .NET6.0 and above)
EasyCompressor.LZ4⭐️ Algorithm: LZ4
Extremely Fast (Recommended - see Benchmarks)
EasyCompressor.Snappier⭐️ Algorithm: Snappy
Extremely Fast (Recommended - see Benchmarks)
EasyCompressor.ZstdSharp⭐️ Algorithm: Zstd (Zstandard)
Extremely Fast (Recommended - see Benchmarks)
EasyCompressor.LZMA Algorithm: LZMA
High compression ratio (small size) but very Slow (Not recommended - see Benchmarks)
EasyCompressor.Zstd (deprecated) Instead, use EasyCompressor.ZstdSharp.
EasyCompressor.Snappy (deprecated) Instead, use EasyCompressor.Snappier
EasyCompressor.BrotliNET (deprecated) Instead, use BrotliCompressor in EasyCompressor itself (base package)
(Use only if your project targets .NETFramework462 and above or .NETCoreApp2.0)
EasyCaching.Extensions.EasyCompressor⭐️ A winning combination by integrating with EasyCaching to compress your cache data. (Recommended)
See How to use

Note :

All of these packages are cross-platform except EasyCompressor.Zstd and EasyCompressor.Snappy which are not cross-platform because their underlying library are just a wrapper around the native dlls only for windows.

Get Started

1. Install Package

PM> Install-Package EasyCompressor.LZ4

PM> # Install-Package EasyCompressor (for Brotli, GZip, Deflate, ZLib)
PM> # Install-Package EasyCompressor.Snappier
PM> # Install-Package EasyCompressor.ZstdSharp
PM> # Install-Package EasyCompressor.LZMA
PM> # Install-Package EasyCompressor.Zstd (deprecated)
PM> # Install-Package EasyCompressor.Snappy (deprecated)
PM> # Install-Package EasyCompressor.BrotliNET (deprecated)

2. Using New Instance or the Shared Instance

public class YourClass
{
    private readonly ICompressor _compressor;

    public YourClass()
    {
        //--------------------------------------- New Instance ---------------------------------------
        _compressor = new LZ4Compressor();            //package : EasyCompressor.LZ4

        //_compressor = new ZstdSharpCompressor();    //package : EasyCompressor.Snappier
        //_compressor = new BrotliCompressor();       //package : EasyCompressor
        //_compressor = new GZipCompressor();         //package : EasyCompressor
        //_compressor = new DeflateCompressor();      //package : EasyCompressor
        //_compressor = new ZLibCompressor();         //package : EasyCompressor
        //_compressor = new LZMACompressor();         //package : EasyCompressor.LZMA
        //_compressor = new ZstdCompressor();         //package : EasyCompressor.Zstd (deprecated)
        //_compressor = new SnappyCompressor();       //package : EasyCompressor.Snappy (deprecated)
        //_compressor = new BrotliNETCompressor();    //package : EasyCompressor.BrotliNET (deprecated)


        //--------------------------------------- Shared Instance ---------------------------------------
        _compressor = LZ4Compressor.Shared;            //package : EasyCompressor.LZ4

        //_compressor = ZstdSharpCompressor.Shared;    //package : EasyCompressor.Snappier
        //_compressor = BrotliCompressor.Shared;       //package : EasyCompressor
        //_compressor = GZipCompressor.Shared;         //package : EasyCompressor
        //_compressor = DeflateCompressor.Shared;      //package : EasyCompressor
        //_compressor = ZLibCompressor.Shared;         //package : EasyCompressor
        //_compressor = LZMACompressor.Shared;         //package : EasyCompressor.LZMA
        //_compressor = ZstdCompressor.Shared;         //package : EasyCompressor.Zstd (deprecated)
        //_compressor = SnappyCompressor.Shared;       //package : EasyCompressor.Snappy (deprecated)
        //_compressor = BrotliNETCompressor.Shared;    //package : EasyCompressor.BrotliNET (deprecated)
    }

    static static void ProcessData(byte[] bytes)
    {
        // Compress your original byte[] and return compressed byte[]
        var compressedBytes = _compressor.Compress(bytes);

        // Decompress compressed byte[] and return uncompressed byte[]
        var uncompressedBytes = _compressor.Decompress(compressedBytes);
    }

    public static void ProcessStream(Stream input, stream output)
    {
        // Read input stream and Compress into output stream
        _compressor.Compress(input, output);

        // Read input stream and Decompress into output stream
        _compressor.Decompress(input, output);
    }
}

3. Using Dependency Injection

Add Services

public void ConfigureServices(IServiceCollection services)
{
    //...
    services.AddLZ4Compressor();            //package : EasyCompressor.LZ4

    //services.AddSnappierCompressor();     //package : EasyCompressor.Snappier
    //services.AddZstdSharpCompressor();    //package : EasyCompressor.ZstdSharp
    //services.AddBrotliCompressor();       //package : EasyCompressor
    //services.AddGZipCompressor();         //package : EasyCompressor
    //services.AddDeflateCompressor();      //package : EasyCompressor
    //services.AddZLibCompressor();         //package : EasyCompressor
    //services.AddLZMACompressor();         //package : EasyCompressor.LZMA
    //services.AddZstdCompressor();         //package : EasyCompressor.Zstd (deprecated)
    //services.AddSnappyCompressor();       //package : EasyCompressor.Snappy (deprecated)
    //services.AddBrotliNETCompressor();    //package : EasyCompressor.BrotliNET (deprecated)
}

Inject/Resolve it and use it

using EasyCompressor;

public class YourClass
{
    private readonly ICompressor _compressor;

    public YourClass(ICompressor compressor) //Inject using dependency injection
    {
        _compressor = compressor;
        //Or resolve it using IServiceProvider
        //_compressor = serviceProvider.GetService<ICompressor>()
    }

    public void ProcessData(byte[] bytes)
    {
        // Compress your original byte[] and return compressed byte[]
        var compressedBytes = _compressor.Compress(bytes);

        // Decompress compressed byte[] and return uncompressed byte[]
        var uncompressedBytes = _compressor.Decompress(compressedBytes);
    }

    public void ProcessStream(Stream input, stream output)
    {
        // Read input stream and Compress into output stream
        _compressor.Compress(input, output);

        // Read input stream and Decompress into output stream
        _compressor.Decompress(input, output);
    }
}

4. Using Named Instances

Register Named compressors

public void ConfigureServices(IServiceCollection services)
{
    //...
    services.AddLZ4Compressor("lz4");                 //package : EasyCompressor.LZ4
    services.AddSnappierCompressor("snappier");       //package : EasyCompressor.Snappier
    services.AddZstdSharpCompressor("zstdsharp");     //package : EasyCompressor.ZstdSharp

    //services.AddBrotliCompressor("brotli");         //package : EasyCompressor
    //services.AddGZipCompressor("gzip");             //package : EasyCompressor
    //services.AddDeflateCompressor("deflate");       //package : EasyCompressor
    //services.AddZLibCompressor("zlib");             //package : EasyCompressor
    //services.AddLZMACompressor("lzma");             //package : EasyCompressor.LZMA
    //services.AddZstdCompressor("zstd");             //package : EasyCompressor.Zstd (deprecated)
    //services.AddSnappyCompressor("snappy");         //package : EasyCompressor.Snappy (deprecated)
    //services.AddBrotliNETCompressor("brotlinet");   //package : EasyCompressor.BrotliNET (deprecated)
}

Resolve it using ICompressorProvider

using EasyCompressor;

public class YourClass
{
    private readonly ICompressor _lz4Compressor;
    private readonly ICompressor _snappierCompressor;
    private readonly ICompressor _zstdsharpCompressor;

    public YourClass(ICompressorProvider compressorProvider)
    {
        _lz4Compressor = compressorProvider.GetCompressor("lz4");
        _snappierCompressor = compressorProvider.GetCompressor("snappier");
        _zstdsharpCompressor = compressor.GetCompressor("zstdsharp");
    }
}

Benchmarks

👉 To view the Full benchmark, visit this HTML Page. 👈

Benchmark

Other Benchmarks

Compressing/Decompressing Binary Data (byte[])

Compressing/Decompressing Stream Data

Compressing/Decompressing Stream Data (Async)

Key Results and Conclusion

Best Compressors based on Overall Performance (Speed and Memory Allocation) in each case

Operation Binary Stream StreamAsync
Compress SnappierCompressor
LZ4Compressor
ZstdSharpCompressor
SnappierCompressor
LZ4Compressor
BrotliCompressor
LZ4Compressor
BrotliCompressor
Decompress LZ4Compressor
SnappierCompressor
ZstdSharpCompressor
SnappierCompressor
LZ4Compressor
ZstdSharpCompressor
ZstdSharpCompressor
LZ4Compressor

Best Compressors based on Highest compression (Smallest size)

  1. BrotliCompressor (smaller in medium/small data with moderate speed and memory usage)
  2. LZMACompressor (smaller in large data but very slow and memory inefficient)
  3. ZstdSharpCompressor (fastest meanwhile with acceptable/good enough level of compression)

Benchmark

BenchmarkDotNetVisualizer🌈

All the benchmarks are visualized using BenchmarkDotNetVisualizer.

What’s Changed from v1.4.0 to v2.0.2

Full Changelog: https://github.com/mjebrahimi/EasyCompressor/compare/1.4.0…2.0.2

Todo

Open an issue or discussion and tell me which integration or feature you like the most.

Contributing

Create an issue or discussion if you found a BUG or have a Suggestion or Question.

Or if you want to develop this project:

  1. Fork it
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request

Give a Star! ⭐️

If you find this repository useful and like it, why not give it a star? if not, never mind! :)

License

Copyright © 2020 Mohammad Javad Ebrahimi under the MIT License.