Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#
Tip/Trick

How to compress/decompress directories using GZipStream

Rate me:
Please Sign up or sign in to vote.
4.89/5 (21 votes)
25 Jan 2012CPOL 150.3K   21   14
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:

C#
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.


C#
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)


Written By
Web Developer
United States United States
Programmer since 1990.

Comments and Discussions

 
PraiseWorks like a charm Pin
Tech Code Freak15-Sep-19 3:08
Tech Code Freak15-Sep-19 3:08 
Questionsystem.outOfMemory Exception Pin
Member 312041427-Feb-17 21:14
Member 312041427-Feb-17 21:14 
BugReg:Directory Compression Pin
Member 110323613-Apr-15 18:49
Member 110323613-Apr-15 18:49 
QuestionI unzipped manually and got a file with no extension Pin
Kumar Tanmay22-Dec-14 23:12
Kumar Tanmay22-Dec-14 23:12 
AnswerRe: I unzipped manually and got a file with no extension Pin
Andrew Novik23-Dec-14 6:27
Andrew Novik23-Dec-14 6:27 
GeneralNice Code Pin
Аslam Iqbal31-Jan-14 2:50
professionalАslam Iqbal31-Jan-14 2:50 
GeneralMy vote of 5 Pin
Thé Dèvíl 201312-Apr-13 2:11
Thé Dèvíl 201312-Apr-13 2:11 
GeneralMy vote of 5 Pin
David Catriel6-Mar-13 10:54
David Catriel6-Mar-13 10:54 
QuestionProblem getting this to work. Pin
Tom Cusick8-Feb-13 9:45
Tom Cusick8-Feb-13 9:45 
AnswerRe: Problem getting this to work. Pin
Andrew Novik11-Feb-13 5:46
Andrew Novik11-Feb-13 5:46 
QuestionHow to compree directories? Pin
Ar.Gorgin30-Sep-12 18:57
Ar.Gorgin30-Sep-12 18:57 
GeneralDotNet zip can do security attributes and encryption and gen... Pin
Dean Oliver1-Feb-12 8:12
Dean Oliver1-Feb-12 8:12 
GeneralReason for my vote of 1 a bit unnecessary there are api's th... Pin
Dean Oliver31-Jan-12 18:33
Dean Oliver31-Jan-12 18:33 
Reason for my vote of 1
a bit unnecessary there are api's that do this out the box.
GeneralRe: Thanks for the alternative - DotNetZip is pretty useful libr... Pin
Andrew Novik1-Feb-12 5:58
Andrew Novik1-Feb-12 5:58 

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

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