Tips and tricks for Windows 8 JavaScript (and C# !) developers: Use compression API to save disk space

I love JSON format. It is human readable and really fast to serialize to and deserialize from. However the major drawback of JSON is its size on disk.

The following code will show you how to leverage System.IO.Compression (from .NET) to reduce the disk footprint of your JSON files.

To do so, just create a .NET WinRT component with this code:

public static class Compression
{
    public static IAsyncOperation<IList<byte>> Compress(string data)
    {
        return AsyncInfo.Run(async (ct) =>
            {
                UTF8Encoding encoding = new UTF8Encoding();
                using (MemoryStream zipMemoryStream = new MemoryStream())
                {
                    using (ZipArchive zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Create))
                    {
                        var buffer = encoding.GetBytes(data);
                        ZipArchiveEntry entry = zipArchive.CreateEntry("flipflop");
                        using (Stream entryStream = entry.Open())
                        {
                            await entryStream.WriteAsync(buffer, 0, buffer.Length);
                        }
                    }

                    return (IList<byte>)zipMemoryStream.ToArray();
                }
            });
    }

    public static IAsyncOperation<string> Decompress([ReadOnlyArray] byte[] data)
    {
        return AsyncInfo.Run(async (ct) =>
            {
                UTF8Encoding encoding = new UTF8Encoding();
                using (MemoryStream zipMemoryStream = new MemoryStream(data))
                {
                    using (ZipArchive zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Read))
                    {
                        ZipArchiveEntry entry = zipArchive.GetEntry("flipflop");
                        using (Stream entryStream = entry.Open())
                        {
                            byte[] result = new byte[entry.Length];
                            var offset = 0;
                            var globalOffset = 0;
                            do
                            {
                                offset = await entryStream.ReadAsync(result, globalOffset, result.Length - globalOffset);
                                globalOffset += offset;
                            }
                            while (offset > 0);
                            return encoding.GetString(result, 0, result.Length);
                        }
                    }
                }
            });
    }
}

Two thing worth noting here:

  • The usage of IAsyncOperation to make your component compliant with WinRT asynchronous calls (it will generate a promise for JavaScript)
  • The usage of ZipArchive to create in memory compressed streams

The beauty appears when it comes to use this code from JavaScript:

=> Reading compressed data:

 Windows.Storage.FileIO.readBufferAsync(file).then(function (buffer) {
     if (buffer) {
         var reader = new Windows.Storage.Streams.DataReader.fromBuffer(buffer);
         var data = new Array(buffer.length);
         reader.readBytes(data);
         Utilities.Compression.decompress(data).then(function (decompressedData) {
        var mvar myData = JSON.parse(decompressedData);

         });
     }
 });

=> Writing compressed data:

var picker = new Windows.Storage.Pickers.FileSavePicker();
picker.fileTypeChoices.insert("Toto files", [".toto"]);
picker.pickSaveFileAsync().then(function (file) {
    if (file != null) {
        var data = JSON.stringify(myData);

        Utilities.Compression.compress(data).then(function (compressedData) {
            var uint8 = new Uint8Array(compressedData);
            Windows.Storage.FileIO.writeBytesAsync(file, uint8).then(function () {
                // Notify success
             });
        });
    }
});

Isn’t it beautiful when .NET and JavaScript work together? Sourire