268

I am trying to programatically unzip a zipped file.

I have tried using the System.IO.Compression.GZipStream class in .NET, but when my app runs (actually a unit test) I get this exception:

System.IO.InvalidDataException: The magic number in GZip header is not correct. Make sure you are passing in a GZip stream..

I now realize that a .zip file is not the same as a .gz file, and that GZip is not the same as Zip.

However, since I'm able to extract the file by manually double clicking the zipped file and then clicking the "Extract all files"-button, I think there should be a way of doing that in code as well.

Therefore I've tried to use Process.Start() with the path to the zipped file as input. This causes my app to open a Window showing the contents in the zipped file. That's all fine, but the app will be installed on a server with none around to click the "Extract all files"-button.

So, how do I get my app to extract the files in the zipped files?

Or is there another way to do it? I prefer doing it in code, without downloading any third party libraries or apps; the security department ain't too fancy about that...

gunr2171
  • 16,104
  • 25
  • 61
  • 88
Petteri
  • 2,701
  • 2
  • 16
  • 7
  • 17
    Your security department is happier with you writing your own code for something than using a library that has been debugged and looked at by presumably many eyes? You can use a library AND "do it in code" (get the source and compile it yourself) but I see reinventing the wheel as a bigger problem than any security issues brought about by using a tried and true library. – Jared Updike May 07 '09 at 20:10
  • 11
    @Jared - When management gets an idea in their head... – Steven Evers May 07 '09 at 20:16
  • 5
    There is less risk for security department if you get a third party product. Just download dotnetzip and rename it "[insert company name].ziplibrary.dll" – Simon May 07 '09 at 21:41

15 Answers15

565

With .NET 4.5 you can now unzip files using the .NET framework:

using System;
using System.IO;

namespace ConsoleApplication
{
  class Program
  {
    static void Main(string[] args)
    {
      string startPath = @"c:\example\start";
      string zipPath = @"c:\example\result.zip";
      string extractPath = @"c:\example\extract";

      System.IO.Compression.ZipFile.CreateFromDirectory(startPath, zipPath);
      System.IO.Compression.ZipFile.ExtractToDirectory(zipPath, extractPath);
    }
  }
}

The above code was taken directly from Microsoft's documentation: http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx

ZipFile is contained in the assembly System.IO.Compression.FileSystem. (Thanks nateirvin...see comment below). You need to add a DLL reference to the framework assembly System.IO.Compression.FileSystem.dll

LCJ
  • 22,196
  • 67
  • 260
  • 418
bsara
  • 7,940
  • 3
  • 29
  • 47
  • 133
    BTW, `ZipFile` is contained in the assembly `System.IO.Compression.FileSystem`. – nateirvin Feb 13 '13 at 23:08
  • 78
    Which means that you need to add a DLL reference to the framework assembly `System.IO.Compression.FileSystem.dll`. – Chris Schiffhauer Aug 13 '13 at 23:50
  • what about .rar files. above code fails to extract .rar files. – Raghu Apr 10 '17 at 11:27
  • 2
    I tried this in my asp.net core web api, it read first entry fine, but on second entry it always give error `A local file header is corrupt`. Any though on this? – SoftSan May 25 '17 at 19:11
  • Same with @SoftSan. I got also that error. What to do? – Rich May 22 '18 at 07:49
  • This does not preserve file permissions on unix based systems, so I'd suggest not using it if you need to work on Macs or Linux. – Aidan Feb 08 '19 at 17:57
  • 1
    @Aidan that's good to know, though, it would be a good recommendation to not use .NET on Mac/Linux if at all possible. Where it isn't, this is helpful. Thanks. – bsara Feb 25 '19 at 23:57
  • At 2021, you can directly install the Sytem.IO.Compression NuGet package from package manager rather than attaching the dll manually in reference. – Chandraprakash Nov 27 '21 at 17:13
134

For .Net 4.5+

It is not always desired to write the uncompressed file to disk. As an ASP.Net developer, I would have to fiddle with permissions to grant rights for my application to write to the filesystem. By working with streams in memory, I can sidestep all that and read the files directly:

using (ZipArchive archive = new ZipArchive(postedZipStream))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
         var stream = entry.Open();
         //Do awesome stream stuff!!
    }
}

Alternatively, you can still write the decompressed file out to disk by calling ExtractToFile():

using (ZipArchive archive = ZipFile.OpenRead(pathToZip))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
        entry.ExtractToFile(Path.Combine(destination, entry.FullName));
    }
} 

To use the ZipArchive class, you will need to add a reference to the System.IO.Compression namespace and to System.IO.Compression.FileSystem.

David
  • 369
  • 3
  • 14
Mister Epic
  • 16,295
  • 13
  • 76
  • 147
  • 11
    Did it really take MSFT until 4.5+ to add a native decompressor? – JWP Jun 10 '15 at 21:21
  • 2
    @JohnPeters GZipStream was added back in .Net 2.0 (https://msdn.microsoft.com/en-us/library/system.io.compression.gzipstream(v=vs.80).aspx). However, it didn't make it easy to work with multiple files in an archive in memory. The new `ZipArchive` object fits the bill nicely. – Mister Epic Jun 11 '15 at 14:31
  • 2
    This is a particularly good alternative because it allows unzipping **without using the file-system** (in my case I am working with embedded resources), and it's also not a third-party extension. – ANeves Nov 10 '15 at 17:05
  • I tried this in my asp.net core web api, it read first entry fine, but on second entry it always give error `A local file header is corrupt`. Any though on this? – SoftSan May 25 '17 at 19:10
  • 4
    Why should I use a `foreach` loop to `ExtractToFile` when I can just use `ZipFile.ExtractToDirectory(inputFile, outputDir);` What is the advantage of the first method? – The Fluffy Robot Aug 09 '17 at 18:25
  • 1
    in .NET 4.6.1 i am not able to get 'ZipArchive' from 'System.IO.Compression.FileSystem', any Idea? – Ravi Anand Feb 07 '18 at 21:39
  • doesn't work if i concatenate a zip file to another file ( say for example `copy \b file1.mp3 + file2.zip file1.mp3` ) – mrid Apr 25 '18 at 11:56
  • This is great for anyone working on .net standard / core and needs to uncompress a stream instead of a file, as the main nuget packages for working with zip files are not .net standard. – Kyle Jul 12 '18 at 00:00
  • I had the error `'ZipArchiveEntry' does not contain a definition for 'ExtractToFile'` and I found out that, instead, I have to use the static method `System.IO.Compression.ZipFileExtensions.ExtractToFile`. – nonzaprej Aug 06 '18 at 09:16
  • I imported System.IO.Compression, but received this error on build: Error 1 The type or namespace name 'ZipArchive' could not be found (are you missing a using directive or an assembly reference?) C:\Users\Josh\Desktop\delete\WindowsFormsApplication2\WindowsFormsApplication2\Form1.cs 45 25 WindowsFormsApplication2 – Kairan Nov 16 '18 at 22:40
66

We have used SharpZipLib successfully on many projects. I know it's a third party tool, but source code is included and could provide some insight if you chose to reinvent the wheel here.

Chris Conway
  • 16,269
  • 23
  • 96
  • 113
  • 3
    I tried using SharpZipLib and it worked fine. I guess I'll have to see if the prohibition against third party libs and apss is a strict rule or more of a guidline. – Petteri May 07 '09 at 21:49
  • 11
    I don't know about your company, but my experience has always been that it's possible to get an exception to that sort of rule if you write up a *business case* description of why you want the exception. Point out the cost savings v. DIY, as well as the fact that the source can be examined. As a fallback, you can often get permission to use the source even if they won't let you use the dll--then just compile it yourself (or at least the parts you actually need to use...). – RolandTumble May 07 '09 at 22:09
  • You don't have to use external libraries to uncompress zip files, you could use Shell32 from System32. Please see http://stackoverflow.com/a/43066281/948694 – arturn Mar 28 '17 at 09:58
  • 1
    **Code example**: https://stackoverflow.com/a/22444096/273455 – Glebka Jun 02 '21 at 10:21
60

Free, and no external DLL files. Everything is in one CS file. One download is just the CS file, another download is a very easy to understand example. Just tried it today and I can't believe how simple the setup was. It worked on first try, no errors, no nothing.

https://github.com/jaime-olivares/zipstorer

Apolo
  • 3,844
  • 1
  • 21
  • 51
Lukas
  • 2,885
  • 2
  • 29
  • 31
  • Spoke too soon! I want to inflate the files from an http download stream instantly. This does not work since it is using Seek operations on the stream :( Well, thanks to the source code I can write my own ZipStream now... – oyophant Mar 11 '14 at 10:34
  • the best solution to my problem,since im writing an updater app and i cant involve any DLLs in the extraction process since then i would have to update those too....this is good.thank you ! – Niklas Jun 28 '16 at 18:06
  • Answer deserves +100 bounty. Dependency was minimal, best compatible and easy to learn. – Gray Programmerz Jul 26 '22 at 10:49
28

Use the DotNetZip library at http://www.codeplex.com/DotNetZip

class library and toolset for manipulating zip files. Use VB, C# or any .NET language to easily create, extract, or update zip files...

DotNetZip works on PCs with the full .NET Framework, and also runs on mobile devices that use the .NET Compact Framework. Create and read zip files in VB, C#, or any .NET language, or any scripting environment...

If all you want is a better DeflateStream or GZipStream class to replace the one that is built-into the .NET BCL, DotNetZip has that, too. DotNetZip's DeflateStream and GZipStream are available in a standalone assembly, based on a .NET port of Zlib. These streams support compression levels and deliver much better performance than the built-in classes. There is also a ZlibStream to complete the set (RFC 1950, 1951, 1952)...

gnat
  • 6,213
  • 108
  • 53
  • 73
Sam Axe
  • 33,313
  • 9
  • 55
  • 89
  • 2
    Hmmm... But that's a third party library! – Petteri May 07 '09 at 20:51
  • 31
    How very observant of you. Unless you feel like spending several months implemening your own Zip file reader, its your best option. – Sam Axe May 07 '09 at 21:08
  • This one is way better than SharpZipLib – Kugel Oct 02 '13 at 03:55
  • @Dan-o Why not Microsoft Compression? https://www.nuget.org/packages/Microsoft.Bcl.Compression – Mikael Dúi Bolinder Mar 11 '14 at 00:32
  • 5
    Your're asking me questions about an answer that is nearly 5 years old. Do some research. I'm sure you will find an answer. – Sam Axe Mar 11 '14 at 22:28
  • @Kugel this is not a dig, but how in your opinion is it better? I'm considering changing over but gathering knowledge before I do? – Phil Cooper Feb 23 '17 at 17:26
  • 2
    @PhilCooper This is a very old question I recommend using the built-in System.IO.Compression.ZipFile. IIRC I had really bad experiences with SharpZipLib in the past based on my experience of producing thousands of zips on the fly. – Kugel Feb 28 '17 at 06:09
  • @Kugel appreciate your response, I'll give it a try. – Phil Cooper Feb 28 '17 at 11:23
12
String ZipPath = @"c:\my\data.zip";
String extractPath = @"d:\\myunzips";
ZipFile.ExtractToDirectory(ZipPath, extractPath);

To use the ZipFile class, you must add a reference to the System.IO.Compression.FileSystem assembly in your project

Mahadev Mane
  • 810
  • 8
  • 11
  • 1
    Source: https://msdn.microsoft.com/en-us/library/system.io.compression.zipfile(v=vs.110).aspx – gkubed Oct 03 '17 at 14:38
4

This will do it System.IO.Compression.ZipFile.ExtractToDirectory(ZipName, ExtractToPath)

Ilya Kochetov
  • 17,988
  • 6
  • 44
  • 60
2

I use this to either zip or unzip multiple files. The Regex stuff is not required, but I use it to change the date stamp and remove unwanted underscores. I use the empty string in the Compress >> zipPath string to prefix something to all files if required. Also, I usually comment out either Compress() or Decompress() based on what I am doing.

using System;
using System.IO.Compression;
using System.IO;
using System.Text.RegularExpressions;

namespace ZipAndUnzip
{
    class Program
    {
        static void Main(string[] args)
        {
            var directoryPath = new DirectoryInfo(@"C:\your_path\");

            Compress(directoryPath);
            Decompress(directoryPath);
        }

        public static void Compress(DirectoryInfo directoryPath)
        {
            foreach (DirectoryInfo directory in directoryPath.GetDirectories())
            {
                var path = directoryPath.FullName;
                var newArchiveName = Regex.Replace(directory.Name, "[0-9]{8}", "20130913");
                newArchiveName = Regex.Replace(newArchiveName, "[_]+", "_");
                string startPath = path + directory.Name;
                string zipPath = path + "" + newArchiveName + ".zip";

                ZipFile.CreateFromDirectory(startPath, zipPath);
            }

        }

        public static void Decompress(DirectoryInfo directoryPath)
        {
            foreach (FileInfo file in directoryPath.GetFiles())
            {
                var path = directoryPath.FullName;
                string zipPath = path + file.Name;
                string extractPath = Regex.Replace(path + file.Name, ".zip", "");

                ZipFile.ExtractToDirectory(zipPath, extractPath);
            }
        }


    }
}
  • 1
    This requires dot net 4.5 - just a note as others who answered with ZipFile noted and I am still using 3.5. – Thronk Oct 29 '14 at 19:18
2

You can do it all within .NET 3.5 using DeflateStream. The thing lacking in .NET 3.5 is the ability to process the file header sections that are used to organize the zipped files. PKWare has published this information, which you can use to process the zip file after you create the structures that are used. It is not particularly onerous, and it a good practice in tool building without using 3rd party code.

It isn't a one line answer, but it is completely doable if you are willing and able to take the time yourself. I wrote a class to do this in a couple of hours and what I got from that is the ability to zip and unzip files using .NET 3.5 only.

2

Standard zip files normally use the deflate algorithm.

To extract files without using third party libraries use DeflateStream. You'll need a bit more information about the zip file archive format as Microsoft only provides the compression algorithm.

You may also try using zipfldr.dll. It is Microsoft's compression library (compressed folders from the Send to menu). It appears to be a com library but it's undocumented. You may be able to get it working for you through experimentation.

Kenneth Cochran
  • 11,954
  • 3
  • 52
  • 117
  • I'm trying out the DeflateStream class. This time I get System.IO.InvalidDataException: Block length does not match with its complement.. – Petteri May 07 '09 at 20:48
  • As I said above, Microsoft only provided the algorithm. You'll need info on the zip archive format as well. http://en.wikipedia.org/wiki/ZIP_(file_format) should get you started. See the references at the bottom of the page for links to more detailed info. – Kenneth Cochran May 07 '09 at 20:58
  • 2
    I also stumbled acrossed System.IO.Packaging.Package in .NET 3.5. It looks like it may do the trick though its not very intuitive. – Kenneth Cochran May 07 '09 at 21:01
1

From here :

Compressed GZipStream objects written to a file with an extension of .gz can be decompressed using many common compression tools; however, this class does not inherently provide functionality for adding files to or extracting files from .zip archives.

RedWolves
  • 10,379
  • 12
  • 49
  • 68
0

I found out about this one (Unzip package on NuGet) today, since I ran into a hard bug in DotNetZip, and I realized there hasn't been really that much work done on DotNetZip for the last two years.

The Unzip package is lean, and it did the job for me - it didn't have the bug that DotNetZip had. Also, it was a reasonably small file, relying upon the Microsoft BCL for the actual decompression. I could easily make adjustments which I needed (to be able to keep track of the progress while decompressing). I recommend it.

Per Lundberg
  • 3,837
  • 1
  • 36
  • 46
0

From Embed Ressources:

using (Stream _pluginZipResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(programName + "." + "filename.zip"))
{
    using (ZipArchive zip = new ZipArchive(_pluginZipResourceStream))
    {
        zip.ExtractToDirectory(Application.StartupPath);
    }
}
0

Until now, I was using cmd processes in order to extract an .iso file, copy it into a temporary path from server and extracted on a usb stick. Recently I've found that this is working perfectly with .iso's that are less than 10Gb. For a iso like 29Gb this method gets stuck somehow.

    public void ExtractArchive()
    {
        try
        {

            try
            {
                Directory.Delete(copyISOLocation.OutputPath, true); 
            }
            catch (Exception e) when (e is IOException || e is UnauthorizedAccessException)
            {
            }

            Process cmd = new Process();
            cmd.StartInfo.FileName = "cmd.exe";
            cmd.StartInfo.RedirectStandardInput = true;
            cmd.StartInfo.RedirectStandardOutput = true;
            cmd.StartInfo.CreateNoWindow = true;
            cmd.StartInfo.UseShellExecute = false;
            cmd.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

            //stackoverflow
            cmd.StartInfo.Arguments = "-R";

            cmd.Disposed += (sender, args) => {
                Console.WriteLine("CMD Process disposed");
            };
            cmd.Exited += (sender, args) => {
                Console.WriteLine("CMD Process exited");
            };
            cmd.ErrorDataReceived += (sender, args) => {
                Console.WriteLine("CMD Process error data received");
                Console.WriteLine(args.Data);
            };
            cmd.OutputDataReceived += (sender, args) => {
                Console.WriteLine("CMD Process Output data received");
                Console.WriteLine(args.Data);
            };

            //stackoverflow


            cmd.Start();

            cmd.StandardInput.WriteLine("C:");
            //Console.WriteLine(cmd.StandardOutput.Read());
            cmd.StandardInput.Flush();

            cmd.StandardInput.WriteLine("cd C:\\\"Program Files (x86)\"\\7-Zip\\");
            //Console.WriteLine(cmd.StandardOutput.ReadToEnd());
            cmd.StandardInput.Flush();

            cmd.StandardInput.WriteLine(string.Format("7z.exe x -o{0} {1}", copyISOLocation.OutputPath, copyISOLocation.TempIsoPath));
            //Console.WriteLine(cmd.StandardOutput.ReadToEnd());
            cmd.StandardInput.Flush();
            cmd.StandardInput.Close();
            cmd.WaitForExit();
            Console.WriteLine(cmd.StandardOutput.ReadToEnd());
            Console.WriteLine(cmd.StandardError.ReadToEnd());
Răzvan Bălan
  • 33
  • 1
  • 13
0

you can use Info-unzip command line cod.you only need to download unzip.exe from Info-unzip official website.

 internal static void Unzip(string sorcefile)
    {
        try
        {
            AFolderFiles.AFolderFilesDelete.DeleteFolder(TempBackupFolder); // delete old folder   
            AFolderFiles.AFolderFilesCreate.CreateIfNotExist(TempBackupFolder); // delete old folder   
           //need to Command command also to export attributes to a excel file
            System.Diagnostics.Process process = new System.Diagnostics.Process();
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
            startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; // window type
            startInfo.FileName = UnzipExe;
            startInfo.Arguments = sorcefile + " -d " + TempBackupFolder;
            process.StartInfo = startInfo;
            process.Start();
            //string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            process.Dispose();
            process.Close();
        }
        catch (Exception ex){ throw ex; }
    }