Saturday, April 13, 2013

C# array compress and decompress with GZipStream

A small utility class for compressing and decompressing using the GZip algorithm that is built into the .NET framework class GZipStream.
The GZipStream class works with streams, so we need to create a stream to be able to use it. I.e. the GZipStream will write to a stream and also read from a stream.

Compress

For the Compress function we will create a MemoryStream and wrapping it with a using statement so that it is correctly disposed when it leaves scope. We nest a creation of a GZipStream and pass it our MemoryStream and set the compression level to optimal.
Available compression levels are

  • Optimal. Can take a little longer, but will compress the data as best as it can
  • Fastest. Will do a fast compression, the data might not be compressed fully, but sometimes this is good enough.
  • NoCompression. Will not compress, just encode it as a gzip
Then it is just to write the byte array to the GZipStream and call the ToArray() function on the MemoryStream to receive the underlying byte array that can be used.


public static class Compression
{
    public static byte[] Compress(byte[] data)
    {
        using (var ms = new MemoryStream())
        {
            using (var gzip = new GZipStream(ms, CompressionLevel.Optimal))
            {
                gzip.Write(data, 0, data.Length);
            }
            data = ms.ToArray();
        }
        return data;
    }
    public static byte[] Decompress(byte[] data)
    {
        // the trick is to read the last 4 bytes to get the length
        // gzip appends this to the array when compressing
        var lengthBuffer = new byte[4];
        Array.Copy(data, data.Length - 4, lengthBuffer, 0, 4);
        int uncompressedSize = BitConverter.ToInt32(lengthBuffer, 0);
        var buffer = new byte[uncompressedSize];
        using (var ms = new MemoryStream(data))
        {
            using (var gzip = new GZipStream(ms, CompressionMode.Decompress))
            {
                gzip.Read(buffer, 0, uncompressedSize);
            }
        }
        return buffer;
    }
}

Decompress

For the decompress part we will start with figuring out the length of the uncompressed size by reading the first four bytes of the input array and converting those to a integer.
After that we create our resulting output byte array to the uncompressed size.
And then again with the MemoryStream and GZipStream, this time we send in the Decompress enum member to specify that we want to decompress the stream.
Note that we call the MemoryStream constructor with the input byte array and that we use the GZipStream to read to the resulting buffer from position 0 to the uncompressed size of the data.

Hope this helps someone out there!


Saturday, March 16, 2013

DateTime.Now vs DateTime.UtcNow

Please note that this post does not take into account any other perspective of when to use DateTime.Now or DateTime.UtcNow other than performance.

This morning I tried to find numbers that compare DateTime.Now and DateTime.UtcNow but all I found was long discussions on the subject of when to use them. So I decided to write a quick sample myself to see.

Last value was 2013-03-16 12:50:18
DateTime.Now:           00:00:06.6733481 for 10000000 iterations
Last value was 2013-03-16 11:50:18
DateTime.UtcNow:        00:00:00.0741262 for 10000000 iterations
DateTime.UtcNow is 1,11% of DateTime.Now




   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          const int iterations = 10000000;
   6:          DateTime dt = DateTime.UtcNow;
   7:          Stopwatch sw = Stopwatch.StartNew();
   8:          for (int i = 0; i < iterations; i++)
   9:              dt = DateTime.Now;
  10:          sw.Stop();
  11:          Console.WriteLine("Last value was {0}", dt);
  12:          Console.WriteLine("DateTime.Now:\t\t{0} for {1} iterations", sw.Elapsed, iterations);
  13:          double nowMs = sw.ElapsedMilliseconds;
  14:          sw = Stopwatch.StartNew();
  15:          for (int i = 0; i < iterations; i++)
  16:              dt = DateTime.UtcNow;
  17:          sw.Stop();
  18:          Console.WriteLine("Last value was {0}", dt);
  19:          Console.WriteLine("DateTime.UtcNow:\t{0} for {1} iterations", sw.Elapsed, iterations);
  20:          double utcNowMs = sw.ElapsedMilliseconds;
  21:          Console.WriteLine("DateTime.UtcNow is {0:0.00}% of DateTime.Now", CalcPercentage(utcNowMs, nowMs));
  22:          Console.ReadLine();
  23:      }
  24:      private static double CalcPercentage(double value, double max)
  25:      {
  26:          double p = (100.0 / max);
  27:          return p * value;
  28:      }
  29:  }