Page 1 of 1

Compressing & decompressing files with C#

#1 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1632
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Posted 26 June 2010 - 07:32 PM

Lately there has been a rash of questions on zipping & unzipping files and folders in C#, so I thought that would be a good topic for a tutorial. When it comes to performing tasks like this you have several options are your disposal. .Net offers this functionality using the System.IO.Compression Namespace, and there are products out there (free and paid) that can help with this as well.

In this tutorial we’ll look at the System.IO.Compression Namespace offered in the .Net Framework for compressing & decompressing files. To create a zip archive with this Namespace is fairly straightforward and easy. We will demonstrate how to create a zip file and how to decompress a zip archive. One drawback of this method, when using the GZipStream class you are compressing a stream, not a file, so there’s no sensible way of handling multiple files because GZip contains no file header information (That’s where libraries like SharpZipLib comes into play, that's a dicsussion for a future tutorial).

For zipping a single file we will use the GZipStream class along with the FileStream class. For this method you will provide 2 parameters:

  • The file to be zipped
  • The name of the resulting zip file


We will open the file to be read, and then create a new stream for the resulting file. We will then create an instance of the GZipStream class and write the contents of the input file to it. This is how this is accomplished with native .Net:

/// <summary>
/// method for compressing a single file into a zip file
/// </summary>
/// <param name="file">the file we're compressing</param>
/// <param name="outputFile">the output zip file</param>
/// <returns></returns>
/// public bool
public bool CompressFile(string file, string outputFile)
{
    try
    {
        //open the file to be compressed
        using (var inFile = File.OpenRead(file))
        {
            //create a new stream from the resulting zip file to be created
            using (var outFile = File.Create(outputFile))
            {
                //now create a GZipStream object for writing the input file to
                using (var compress = new GZipStream(outFile, CompressionMode.Compress, false))
                {
                    //buffer array to hold the input file in
                    byte[] buffer = new byte[inFile.Length];

                    //read the file into the FileStream
                    int read = inFile.Read(buffer, 0, buffer.Length);

                    //now loop (as long as we have data) and
                    //write to the GZipStream
                    while (read > 0)
                    {
                        compress.Write(buffer, 0, read);
                        read = inFile.Read(buffer, 0, buffer.Length);
                    }
                }
            }
        }
        return true;
    }
    catch (IOException ex)
    {
        MessageBox.Show(string.Format("Error compressing file: {0}", ex.Message));
        return false;
    }
}



Decompressing with the GZipStream is a lot like what we did when compressing a file. Your method will expect 2 parameters:

  • The source file (your zip file)
  • The name of the output file


From there we will open two file streams, one for the file being decompressed, and one for the output file. We will then open a new GZipStream object with the CompressionMode of Decompress so we can decompress the underlying stream we're working with. Then as long as we have data in our stream we write it to the output stream, then when it’s completed you will have a file. This is how our decompress method looks:

/// <summary>
/// method for decompressing a zip file
/// </summary>
/// <param name="source">the zip file we're decompressing</param>
/// <param name="destFile">the destination</param>
/// <returns></returns>
public bool Decompress(string source, string destFile)
{
    try
    {
        //open a FileStream from the file we're decompressing
        using (var inStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            //create a FileStream for the resulting output file
            using (var outStream = new FileStream(destFile, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                //Open a GZipStream from the source zip file
                using (var zipStream = new GZipStream(inStream, CompressionMode.Decompress, true))
                {
                    //byte arrya the size of our input file
                    byte[] buffer = new byte[inStream.Length];

                    while (true)
                    {
                        int count = zipStream.Read(buffer, 0, buffer.Length);

                        if (count != 0)
                            outStream.Write(buffer, 0, count);

                        if (count != buffer.Length)
                            // have reached the end
                            break;
                    }
                }
            }
        }
        return true;
    }
    catch (Exception ex)
    {
        // handle or display the error 
        MessageBox.Show(string.Format("Error decompressing file {0}: {1}", source, ex.Message));
        return false;
    }
}



And there you have it, compressing & decompressing files with the System.IO.Compression Namespace in the .Net Framework. In the very near future we’ll take a look at using the SharpZipLib for creating a zip from an entire directory, decompressing a file and adding new files (or an entire directory) to an existing archive file. Thanks for reading 

Is This A Good Question/Topic? 3
  • +

Replies To: Compressing & decompressing files with C#

#2 agent1  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 7
  • View blog
  • Posts: 73
  • Joined: 09-July 10

Posted 14 July 2010 - 10:28 PM

hi psychoCoder

Is there any way to test if a file is already compressed? A user may try to compress an already compressed file..
Will an exception be thrown if an already compressed file is passed as a parameter to the compress method?
Was This Post Helpful? 0
  • +
  • -

#3 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1632
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Posted 14 July 2010 - 10:58 PM

You bring up a good point there. Decompressing an entire file to see if it's compressed (which is one of your options) seems like an awful waste of resources and a lot of work if you ask me. An option you have is this:

All files start with a certain sequence of bytes (example: .zip is "50-4B-03-04", a 4 byte value, a GZip file is “1F-8B-08″ a 3 byte sequence). A full list of signatures can be found here: File Signature Table.

Given this we can write a method, provide it the expected size of the sequence, the actual file and the expected signature, so we could check like this

bool isZipped = isCompressedFile(“testFile.zip”, 4, “50-4B-03-04″);



Our isCompressedFile looks like this:

/// <summary>
/// method for checking if a file is already compressed. Decompressing a file just to determine
/// if the file is already compressed seems like a waste of resources. Most (if not all) files
/// start with a specific sequence of bytes (.zip starts with "50-4B-03-04" a 4 byte value) so we
/// can check for various signatures (a full list can be found at http://www.garykessler.net/library/file_sigs.html
/// </summary>
/// <param name="file">the file we're checking</param>
/// <param name="size">the expected signature size (for example a .zip file would be 4)</param>
/// <param name="expected">the expected signature (for example a .zip file would be "50-4B-03-04")</param>
/// <returns>true is already compressed otherwise false</returns>
public bool isCompressedFile(string file, int size, string expected)
{
    if (string.IsNullOrEmpty(file))
        throw new ArgumentException("You must specify a file to check", "file");

    if (string.IsNullOrEmpty(expected))
        throw new ArgumentException("You must specify an expected signature value","expectedSig");

    //open a file stream
    using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    {
        //check the length of the stream. If it's less
        //than the expected size then it's not compressed
        if (stream.Length < size)
            return false;

        //byte array the size of the expected size of the signature
        byte[] sig = new byte[size];
        int required = size;
        int i = 0;

        while (required > 0)
        {
            int bytesRead = stream.Read(sig, i, required);
            required -= bytesRead;
            i += bytesRead;
        }

        //convert the byte array to a string for comparing to the
        //expected signature to determine if a file is already compressed
        string actual = BitConverter.ToString(sig);

        //now do the comparison
        if (actual.Equals(expected))
            return true;
        else
            return false;
    }

}



So as you can see it is indeed possible to check before compressing/decompressing a file to see if it's already compressed. Hope that helps
Was This Post Helpful? 2
  • +
  • -

Page 1 of 1