C# - Load/save compressed binary files

By , 12/28/2012
(1 ratings)
This snippet simplifies loading and storing any desired data in compressed, binary form.
A demo is available in the XML comment of the BinaryFileIO-class.

The Contracts-class originates from the Microsoft CodeContracts Framework.
http://research.microsoft.com/en-us/projects/contracts/
If you don't have it installed, you can replace these lines with corresponding If-statements.

Author: Rainer Hilmer, translation by Michael List
using System;
using System.Diagnostics.Contracts;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;

namespace Cyrons
{
    /// <summary>
    /// Provides functionality for simple loading/saving
    ///  any desired data in compressed, binary form.
    /// </summary>
    /// <example>
    /// <code>
    /// <![CDATA[
    ///using System;
    ///
    ///namespace CompressorDemo
    ///{
    ///   [Serializable]
    ///   public class DemoDTO
    ///   {
    ///      // A few demo data with different types.
    ///      public Guid ID { get; set; }
    ///      public string Firstname { get; set; }
    ///      public string Lastname { get; set; }
    ///      public DateTime Birthday { get; set; }
    ///   }
    ///}
    ///
    /// ]]>
    /// </code>
    /// </example>
    /// /// <example>
    /// <code>
    /// <![CDATA[
    ///using System;
    ///using System.IO;
    ///using Cyrons;
    ///
    ///namespace CompressorDemo
    ///{
    ///   internal class Program
    ///   {
    ///      static void Main()
    ///      {
    ///         string fullFilename = GetProjectPath(EnvironmentMode.Regular) + @"\Demodata.bin";
    ///
    ///         var compressor =
    ///            new CompressedBinaryFileIO(GetProjectPath(EnvironmentMode.Regular), "Demodata", "bin");
    ///
    ///         //======================================================================
    ///
    ///         SaveDemo(compressor);
    ///
    ///         //======================================================================
    ///
    ///         Console.WriteLine("Now trying to load and decompress...");
    ///         LoadDemo(compressor, fullFilename);
    ///
    ///         //======================================================================
    ///
    ///         // Prevents automatically closing the console window.
    ///         Console.WriteLine("\nPress any key to terminate the program.");
    ///         Console.ReadKey();
    ///      }
    ///
    ///      private static void LoadDemo(CompressedBinaryFileIO compressor, string fullFilename)
    ///      {
    ///         if(File.Exists(fullFilename))
    ///         {
    ///            try
    ///            {
    ///               DemoDTO oldData = compressor.Load() as DemoDTO;
    ///
    ///               if(oldData == null)
    ///                  Console.WriteLine("No data avaliable to process.");
    ///               else
    ///               {
    ///                  Console.WriteLine("ID: {0}", oldData.ID);
    ///                  Console.WriteLine("Firstname: {0}", oldData.Firstname);
    ///                  Console.WriteLine("Lastname: {0}", oldData.Lastname);
    ///                  Console.WriteLine("Birthday: {0}", oldData.Birthday);
    ///               }
    ///            }
    ///            catch(Exception problem)
    ///            {
    ///               Console.WriteLine(problem);
    ///            }
    ///         }
    ///         else
    ///            Console.WriteLine("This file does not exist.");
    ///      }
    ///
    ///      private static void SaveDemo(CompressedBinaryFileIO compressor)
    ///      {
    ///         var data = new DemoDTO
    ///                       {
    ///                          ID = Guid.NewGuid(),
    ///                          Birthday = new DateTime(2009, 7, 5),
    ///                          Lastname = "Demolastname",
    ///                          Firstname = "Demofirstname"
    ///                       };
    ///         try
    ///         {
    ///            compressor.Save(data);
    ///            Console.WriteLine("File has successfully been saved." + Environment.NewLine);
    ///         }
    ///         catch(Exception problem)
    ///         {
    ///            Console.WriteLine(problem);
    ///         }
    ///         finally
    ///         {
    ///            data = null;
    ///         }
    ///      }
    ///
    ///      #region DemoHelper
    ///
    ///      /// <summary>
    ///      /// Gets the path to current project folder.
    ///      /// Please do not use this property in production code.
    ///      /// </summary>
    ///      /// <returns>path to current project folder</returns>
    ///      private static string GetProjectPath(EnvironmentMode mode)
    ///      {
    ///         // Result: Debug- or Release-folder located in the project folder.
    ///         string projectPath = Environment.CurrentDirectory;
    ///         // With each iteration you step one level higher in the directory tree.
    ///         for(int i = 0; i < (int)mode; i++)
    ///         {
    ///            projectPath = Path.GetDirectoryName(projectPath);
    ///         }
    ///         return projectPath;
    ///      }
    ///
    ///      /// <summary>
    ///      /// Depending on the environment the number of levels,
    ///      /// to climb up the directory tree, varies.
    ///      /// </summary>
    ///      private enum EnvironmentMode
    ///      {
    ///         /// <summary>
    ///         /// Climbs up 2 levels in the directory tree.
    ///         /// </summary>
    ///         Regular = 2,
    ///
    ///         /// <summary>
    ///         /// Climbs up 3 levels in the directory tree.
    ///         /// </summary>
    ///         UnitTests = 3
    ///      }
    ///
    ///      #endregion
    ///   }
    ///}
    ///
    /// ]]>
    /// </code>
    /// </example>
    public class CompressedBinaryFileIO
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CompressedBinaryFileIO"/> Class.
        /// </summary>
        /// <param name="path">The filepath,
        ///  into/from where the file is going to be saved or loaded.
        /// (without \ at the end).</param>
        /// <param name="filename">Filename without extension</param>
        /// <param name="extension">Fileextension without preceding dot.</param>
        public CompressedBinaryFileIO(string path, string filename, string extension)
        {
            Contract.Requires(!string.IsNullOrEmpty(path));
            Contract.Requires(!string.IsNullOrEmpty(filename));
            Contract.Requires(!string.IsNullOrEmpty(extension));
            Path = path;
            Filename = filename;
            Extension = extension;
            fullFilename = Path + @"\" + Filename + "." + Extension;
        }

        private static readonly Object syncLock = new Object();
        private readonly string fullFilename;

        /// <summary>
        /// Returns the path that was specified in the constructor.
        /// </summary>
        /// <value>The path.</value>
        public string Path { get; private set; }

        /// <summary>
        /// Returns the filename that was specified in the constructor.
        /// </summary>
        /// <value>The filename.</value>
        public string Filename { get; private set; }

        /// <summary>
        /// Returns the file extension that was specified in the constructor.
        /// </summary>
        /// <value>The extension.</value>
        public string Extension { get; private set; }

        /// <summary>
        /// Loads a compressed file that was specified in the constructor.
        /// This method is thread safe.
        /// </summary>
        /// <exception cref="Exception">Throws exceptions.</exception>
        public object Load()
        {
            lock (syncLock)
            {
                var filePermissions = new FileIOPermission(
                   FileIOPermissionAccess.Read, fullFilename);
                filePermissions.Assert();

                var decompressedStream = new GZipStream(
                   File.OpenRead(fullFilename), CompressionMode.Decompress);
                var formatter = new BinaryFormatter();
                object data = formatter.Deserialize(decompressedStream);
                decompressedStream.Close();
                decompressedStream.Dispose();
                formatter = null;
                return data;
            }
        }


        /// <summary>
        /// Saves a compressed file that was specified in the constructor.
        /// Aborts if passed data is null.
        /// This method is thread safe.
        /// </summary>
        /// <returns>true if data was saved successfully, otherwise false.</returns>
        /// <exception cref="Exception">Throws exceptions.</exception>
        public bool Save(object data)
        {
            lock (syncLock)
            {
                if (data == null)
                    return false;
                var filePermissions = new FileIOPermission(
                   FileIOPermissionAccess.Write, fullFilename);
                filePermissions.Assert();

                var compressedStream = new GZipStream(
                   File.Create(fullFilename), CompressionMode.Compress);
                var formatter = new BinaryFormatter();
                formatter.Serialize(compressedStream, data);
                compressedStream.Close();
                compressedStream.Dispose();
                formatter = null;
                return true;
            }
        }
    }
}

Comments

 

Log in, to comment!