Click here to Skip to main content
Click here to Skip to main content

Tagged as

How to compress/decompress directories using GZipStream

, 25 Jan 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
Very simple console utility to compress/decompress directories uses GZipStream from the System.IO.Compression namespace.

The example contains four independent functions ready for copy/paste:

CompressFile(), CompressDirectory(), DecompressFile(), DecompressToDirectory()
They may inform about progress and don't contain any Console/GUI specific code due to ProgressDelegate.
 
The complete console utility is represented as well. The utility works in both directions. If the first parameter is a directory, then the utility stores all its content to the compressed file (second parameter). If first parameter is a compressed file, the utility restores all files to the destination directory (second parameter).
 
I hope it would be convenient to use.

using System;
using System.Text;
using System.IO;
using System.IO.Compression;
 
namespace CmprDir
{
  class Program
  {
    delegate void ProgressDelegate(string sMessage);
 
    static void CompressFile(string sDir, string sRelativePath, GZipStream zipStream)
    {
      //Compress file name
      char[] chars = sRelativePath.ToCharArray();
      zipStream.Write(BitConverter.GetBytes(chars.Length), 0, sizeof(int));
      foreach (char c in chars)
        zipStream.Write(BitConverter.GetBytes(c), 0, sizeof(char));
 
      //Compress file content
      byte[] bytes = File.ReadAllBytes(Path.Combine(sDir, sRelativePath));
      zipStream.Write(BitConverter.GetBytes(bytes.Length), 0, sizeof(int));
      zipStream.Write(bytes, 0, bytes.Length);
    }
 
    static bool DecompressFile(string sDir, GZipStream zipStream, ProgressDelegate progress)
    {
      //Decompress file name
      byte[] bytes = new byte[sizeof(int)];
      int Readed = zipStream.Read(bytes, 0, sizeof(int));
      if (Readed < sizeof(int))
        return false;
 
      int iNameLen = BitConverter.ToInt32(bytes, 0);
      bytes = new byte[sizeof(char)];
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < iNameLen; i++)
      {
        zipStream.Read(bytes, 0, sizeof(char));
        char c = BitConverter.ToChar(bytes, 0);
        sb.Append(c);
      }
      string sFileName = sb.ToString();
      if (progress != null)
        progress(sFileName);
 
      //Decompress file content
      bytes = new byte[sizeof(int)];
      zipStream.Read(bytes, 0, sizeof(int));
      int iFileLen = BitConverter.ToInt32(bytes, 0);
 
      bytes = new byte[iFileLen];
      zipStream.Read(bytes, 0, bytes.Length);
 
      string sFilePath = Path.Combine(sDir, sFileName);
      string sFinalDir = Path.GetDirectoryName(sFilePath);
      if (!Directory.Exists(sFinalDir))
        Directory.CreateDirectory(sFinalDir);
 
      using (FileStream outFile = new FileStream(sFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
        outFile.Write(bytes, 0, iFileLen);
 
      return true;
    }
 
    static void CompressDirectory(string sInDir, string sOutFile, ProgressDelegate progress)
    {
      string[] sFiles = Directory.GetFiles(sInDir, "*.*", SearchOption.AllDirectories);
      int iDirLen = sInDir[sInDir.Length - 1] == Path.DirectorySeparatorChar ? sInDir.Length : sInDir.Length + 1;
 
      using (FileStream outFile = new FileStream(sOutFile, FileMode.Create, FileAccess.Write, FileShare.None))
      using (GZipStream str = new GZipStream(outFile, CompressionMode.Compress))
        foreach (string sFilePath in sFiles)
        {
          string sRelativePath = sFilePath.Substring(iDirLen);
          if (progress != null)
            progress(sRelativePath);
          CompressFile(sInDir, sRelativePath, str);
        }
    }
 
    static void DecompressToDirectory(string sCompressedFile, string sDir, ProgressDelegate progress)
    {
      using (FileStream inFile = new FileStream(sCompressedFile, FileMode.Open, FileAccess.Read, FileShare.None))
      using (GZipStream zipStream = new GZipStream(inFile, CompressionMode.Decompress, true))
        while (DecompressFile(sDir, zipStream, progress));
    }
 
    public static int Main(string[] argv) 
    {
      if (argv.Length != 2)
      {
        Console.WriteLine("Usage: CmprDir.exe <in_dir compressed_file> | <compressed_file out_dir>");
        return 1;
      }
 
      string sDir;
      string sCompressedFile;
      bool bCompress = false;
      try
      {
        if (Directory.Exists(argv[0]))
        {
          sDir = argv[0];
          sCompressedFile = argv[1];
          bCompress = true;
        }
        else
          if (File.Exists(argv[0]))
          {
            sCompressedFile = argv[0];
            sDir = argv[1];
            bCompress = false;
          }
          else
          {
            Console.Error.WriteLine("Wrong arguments");
            return 1;
          }
 
        if (bCompress)
          CompressDirectory(sDir, sCompressedFile, (fileName) => { Console.WriteLine("Compressing {0}...", fileName); });
        else
          DecompressToDirectory(sCompressedFile, sDir, (fileName) => { Console.WriteLine("Decompressing {0}...", fileName); });
 
        return 0;
      }
      catch (Exception ex)
      {
        Console.Error.WriteLine(ex.Message);
        return 1;
      }
    }
  }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Andrew Novik
Web Developer
United States United States
Programmer since 1990.

Comments and Discussions

 
GeneralNice Code PinmemberАslam Iqbal31-Jan-14 2:50 
GeneralMy vote of 5 PinmemberThé Dèvíl 201312-Apr-13 2:11 
GeneralMy vote of 5 PinmemberDavid Catriel6-Mar-13 10:54 
QuestionProblem getting this to work. PinmemberTom Cusick8-Feb-13 9:45 
AnswerRe: Problem getting this to work. PinmemberAndrew Novik11-Feb-13 5:46 
QuestionHow to compree directories? PinmemberAr.Gorgin30-Sep-12 18:57 
GeneralDotNet zip can do security attributes and encryption and gen... PinmemberDean Oliver1-Feb-12 8:12 
GeneralReason for my vote of 1 a bit unnecessary there are api's th... PinmemberDean Oliver31-Jan-12 18:33 
GeneralRe: Thanks for the alternative - DotNetZip is pretty useful libr... PinmemberAndrew Novik1-Feb-12 5:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.141022.2 | Last Updated 25 Jan 2012
Article Copyright 2012 by Andrew Novik
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid