String Compression And Decompression In C#

When developing applications, you will likely experience strings.

And because string objects are costly in terms of performance, you will often want to compress your string content, i.e., the data inside your string objects, to reduce the payload.

GZip and Brotli are two commonly used methods, however, there are many libraries available to do this.

In this article, we’ll go through how to use the GZip and Brotli algorithms in C# to compress and decompress strings. It is recommended that you have Visual Studio 2022 installed on your system in order to work with the code examples shown here.

In Visual Studio 2022, Create a Console Application Project.

To begin, open Visual Studio and create a.NET Core console application project. Assuming you have Visual Studio 2022 installed, follow the steps below to build a new.NET Core console application project.

  1. Launch the Visual Studio IDE.
  2. Click on “Create a new project.”
  3. In the “Create a new project” window, select “Console App” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window shown next, specify the name and location for the new project.
  6. In the “Additional Information” window, select .NET 6.0 as the runtime and click Next.

Click Create.

This project will be used to show string compression and decompression in the sections that follow. But first, we’ll install BenchmarkDotNet, a benchmarking tool that will allow us to evaluate the benefits of compression.

Install the BenchmarkDotNet NuGet package

This project will be used to show string compression and decompression in the sections that follow. But first, we’ll install BenchmarkDotNet, a benchmarking tool that will allow us to evaluate the benefits of compression.

To use BenchmarkDotNet, you must first install the BenchmarkDotNet package. You may install this with the NuGet Package Manager within Visual Studio 2022, or by executing the following command from the NuGet Package Manager Console:

Install-Package BenchmarkDotNet

The System.IO.Compression namespace in C#

The namespace System.IO.Compression contains methods for compressing files and strings. GZip and Brotli compression algorithms are included. In the sections that follow, we’ll look at how to compress and decompress string data in C# using the GZip and Brotli compression algorithms.

In the following examples, we’ll use the following text:

string originalString = "To work with BenchmarkDotNet you must install the BenchmarkDotNet package. " +
"You can do this either via the NuGet Package Manager inside the Visual Studio 2019 IDE, " +
"or by executing the Install-Package BenchmarkDotNet command at the NuGet Package Manager Console";

Compress and Decompress data using GZip in C#

The following code sample demonstrates how to compress data in C# using the GZipStream class. It’s worth noting that the Compress function takes a byte array as a parameter.

public static byte[] Compress(byte[] bytes)
{
    using (var memoryStream = new MemoryStream())
    {
        using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal))
        {
            gzipStream.Write(bytes, 0, bytes.Length);
        }
        return memoryStream.ToArray();
    }
}

The following method can be used to decompress data that has been compressed using the GZip algorithm.

public static byte[] Decompress(byte[] bytes)
{
    using (var memoryStream = new MemoryStream(bytes))
    {
        using (var outputStream = new MemoryStream())
        {
            using (var decompressStream = new GZipStream(memoryStream, CompressionMode.Decompress))
            {
                 decompressStream.CopyTo(outputStream);
            }
            return outputStream.ToArray();
        }
    }
}

Running the GZip compression algorithm

To use the GZip compression algorithms we just built, use the code snippet below.

byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString);
byte[] compressedData = GZipCompressor.Compress(dataToCompress);
string compressedString = Encoding.UTF8.GetString(compressedData);
Console.WriteLine("Length of compressed string: " + compressedString.Length);
byte[] decompressedData = GZipCompressor.Decompress(compressedData);
string deCompressedString = Encoding.UTF8.GetString(decompressedData);
Console.WriteLine("Length of decompressed string: " + deCompressedString.Length);

When you run the above code, the console window will display the following output.

Length of the original string: 259
Length of the compressed string: 167
Length of the decompressed string: 259

GZip removed 92 characters from the original 259-character string. Because the lengths of the original and decompressed strings should be the same, they should also be the same.

Compress and decompress data using Brotli in C#

The following code sample shows how to compress data in C# using the BrotliStream class. As with the GZip example, the argument to the Compress method is a byte array.

public static byte[] Compress(byte[] bytes)
{
    using (var memoryStream = new MemoryStream())
    {
        using (var brotliStream = new BrotliStream(memoryStream, CompressionLevel.Optimal))
        {
            brotliStream.Write(bytes, 0, bytes.Length);
        }
        return memoryStream.ToArray();
    }
}

And here’s how you can decompress the data with BrotliStream:

public static byte[] Decompress(byte[] bytes)
{
    using (var memoryStream = new MemoryStream(bytes))
    {
         using (var outputStream = new MemoryStream())
         {
              using (var decompressStream = new BrotliStream(memoryStream, CompressionMode.Decompress))
              {
                   decompressStream.CopyTo(outputStream);
              }
              return outputStream.ToArray();
         }
    }
}

Running the Brotli compression algorithm

The code snippet below demonstrates how to compress a string using the Brotli compression method described above.

Console.WriteLine("Length of original string: " + originalString.Length);
byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString);
byte[] compressedData = BrotliCompressor.Compress(dataToCompress);
string compressedString = Convert.ToBase64String(compressedData);
Console.WriteLine("Length of compressed string: " + compressedString.Length);
byte[] decompressedData = BrotliCompressor.Decompress(compressedData);
string deCompressedString = Convert.ToBase64String(decompressedData);
Console.WriteLine("Length of decompressed string: " + deCompressedString.Length);

When you execute the application, the console window will display the following output.

Length of the original string: 259 
Length of the compressed string: 121
Length of the decompressed string: 259

Brotli, as you can see, compresses significantly better than GZip. However, as we’ll see later, the compression ratio isn’t the complete picture.

Asynchronous compression and decompression with GZip and Brotli

It’s worth noting that the compression and decompression algorithms we discussed before have asynchronous analogues. The asynchronous versions of the Compress and Decompress procedures using the GZip algorithm are as follows:

public async static Task<byte[]> CompressAsync(byte[] bytes)
{
    using (var memoryStream = new MemoryStream())
    {
         using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal))
         {
             await gzipStream.WriteAsync(bytes, 0, bytes.Length);
         }
         return memoryStream.ToArray();
    }
}
public async static Task<byte[]> DecompressAsync(byte[] bytes)
{
    using (var memoryStream = new MemoryStream(bytes))
    {
        using (var outputStream = new MemoryStream())
        {
             using (var decompressStream = new GZipStream(memoryStream, CompressionMode.Decompress))
             {
                    await decompressStream.CopyToAsync(outputStream);
             }
             return outputStream.ToArray();
        }
    }
}

Here are the asynchronous variations of the Brotli-based Compress and Decompress methods:

public static async Task<byte[]> CompressAsync(byte[] bytes)
{
    using (var memoryStream = new MemoryStream())
    {
        using (var brotliStream = new BrotliStream(memoryStream, CompressionLevel.Optimal))
        {
            await brotliStream.WriteAsync(bytes, 0, bytes.Length);
        }
        return memoryStream.ToArray();
    }
}
public static async Task<byte[]> DecompressAsync(byte[] bytes)
{
    using (var memoryStream = new MemoryStream(bytes))
    {
        using (var outputStream = new MemoryStream())
        {
            using (var brotliStream = new BrotliStream(memoryStream, CompressionMode.Decompress))
            {
                 await brotliStream.CopyToAsync(outputStream);
            }
            return outputStream.ToArray();
        }
    }
}

Benchmarking compression and decompression with GZip and Brotli in C#

Create a new file called BenchmarkCompression.cs in the console application project that we previously built, and then add the following code to it.

[MemoryDiagnoser]
[Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)]
[RankColumn]
public class BenchmarkCompression
{
     string originalString = "To work with BenchmarkDotNet you must install the BenchmarkDotNet package. " +
            "You can do this either via the NuGet Package Manager inside the Visual Studio 2019 IDE, " +
            "or by executing the Install-Package BenchmarkDotNet command at the NuGet Package Manager Console";

        [Benchmark]
        public void GZipCompress()
        {
            byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString);
            var compressedData = GZipCompressor.Compress(dataToCompress);
        }

        [Benchmark]
        public void BrotliCompress()
        {
            byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString);
            var compressedData = BrotliCompressor.Compress(dataToCompress); 
        }
}

It is obvious that there are other factors to take into account when selecting a compression strategy. Although Brotli offers far greater compression than GZip, the additional compression reduces performance. When it comes to data compression and decompression, GZip beats Brotli.

Always be sure to run your project in release mode while benchmarking your.NET application. The compiler optimizes the code differently for debugging and release modes, which explains the situation.

Submit a Comment

Your email address will not be published. Required fields are marked *

Subscribe

Select Categories