One of the long awaited features in .NET Framework was better support for Zip/archiving. Folks have used third part APIs (most of them are COM API) or Windows COM API to perform zipping, which needless to say has it’s own challenges.
.NET BCL has a namespace called System.IO.Compression (they are part of system assembly) which till .NET 4.0 had two classes –
Both these classes derive from System.IO.Stream class and mainly provide only one type of compression format, which is Deflate. Read this old .NET BCL blog post to know more about System.IO.Compression capabilities.
Now with .NET 4.5, BCL contains a new assembly called System.IO.Compression. You can add a reference to the new assembly using Add Project Reference dialog –
This new assembly contains new classes that provides zip archiving features. These classes are called ZipArchive and ZipArchiveEntry. Both the classes are present in System.IO.Compression Namespace. To use these classes add a using statement in your class file –
using System.IO.Compression;
ZipArchive is the main class that provides zip archiving features – it’s also the entry point into the new API. We would discuss about this class first.
ZipArchive class contains two static methods – ExtractDoDirectory and CreateFromDirectory to handle two of the most used scenarios/use cases –
- ExtractToDirectory extracts all the contents of a zip archive to the specified directory
- CreateFromDirectory takes the contents of the directory and zips it’s content to a zip file
Let’s see examples of both. I have a zip file called MyArchive.zip in C:\Aniruddha\Test\ folder. The zip contains documents of different type –
Let’s try to unzip MyArchive.zip using ExtractToDirectory method of ZipArchive class –
string archiveFilePath = @”C:\Aniruddha\Test\MyArchive.zip”;
string destinationDirectory = @”C:\Aniruddha\Test\Extracted”;
// Pass the zip file location and destinationDirectory to ExtractToDirectory method
ZipArchive.ExtractToDirectory(archiveFilePath, destinationDirectory);
Once this code is run, you’ll find all the contents of zipped file are extracted into Extracted subfolder – if the directory does not exist it would get created.
string destinationArchiveFilePath = @”C:\Aniruddha\Test\MyArchive.zip”;
string sourceDirectory = @”C:\Aniruddha\Test\Source”;
// Pass the source directory and destination archive file path
ZipArchive.CreateFromDirectory(sourceDirectory, destinationArchiveFilePath);
For more sophisticated manipulations of Zip archives, there are two main classes. ZipArchive represents a zip archive, which is a collection of entries, and ZipArchiveEntry represents an archived file entry.
A ZipArchive class (representing a zip file ) can have one or more ZipArchiveEntry class (representing normal files like text file, doc file, pdf file etc) –
string archiveFilePath = @”C:\Aniruddha\Test\MyArchive.zip”;
string sourceFilePath = @”C:\Aniruddha\Test\Test.txt”;
// Create a new ZipArchive specifying zip file location and Archive mode
// Since the archive is created for the first time mode is set as create
// Mode enum value could also be Read and Update
using (ZipArchive archive = new
ZipArchive(archiveFilePath, ZipArchiveMode.Create))
{
// Create the Zip Archive passing an existing file location, file entry name in archive and compression level
// file entry name within archieve file could be different from the original file name
// Compression level could be fastest, no compression and optimal
ZipArchiveEntry archiveEntry = archive.CreateEntryFromFile(sourceFilePath, “Test.txt”, CompressionLevel.Optimal);
}
Note: Dispose has to be called on ZipArchive – either explicitly or implicitly through C# using – if you do not call Dispose the zip archive would not be correctly created. Also since the ZipArchive and related classes internally use unmanaged classes if you do not call Dispose there would be chances of memory issues.
It’s also possible to zip multiple files from different locations using ZipArchiveEntry class. Let’s see an example –
string archiveFilePath = @”C:\Aniruddha\Test\MyArchive.zip”;
string sourceFilePath1 = @”C:\Aniruddha\Test\Test.txt”;
string sourceFilePath2 = @”C:\Articles.docx”;
string sourceFilePath3 = @”C:\CIO_Work\Resume.pdf”;
// Create a new ZipArchive specifying zip file location and Archive mode
// Since the archive is created for the first time mode is set as create
// Mode enum value could also be Read and Update
using (ZipArchive archive = new
ZipArchive(archiveFilePath, ZipArchiveMode.Create))
{
// Create the Zip Archive passing an existing file location, file entry name in archive and compression level
// file entry name within archieve file could be different from the original file name
// Compression level could be fastest, no compression and optimal
ZipArchiveEntry archiveEntry1 = archive.CreateEntryFromFile(sourceFilePath1, Path.GetFileName(sourceFilePath1), CompressionLevel.Optimal);
ZipArchiveEntry archiveEntry2 = archive.CreateEntryFromFile(sourceFilePath2, Path.GetFileName(sourceFilePath2), CompressionLevel.Optimal);
ZipArchiveEntry archiveEntry3 = archive.CreateEntryFromFile(sourceFilePath3, Path.GetFileName(sourceFilePath3), CompressionLevel.Optimal);
}
Using the ZipArchiveEntry class individual file entries of a zip archive can be listed. It provides properties like Name, LastWriteTime, Length (indicates the original file length), CompressedLength.
using (ZipArchive archive = new
ZipArchive(archiveFilePath, ZipArchiveMode.Read))
{
Console.WriteLine(“Name\t\t Size \t Last Write Time\t Comp. Size\t Comp. Ratio”);
foreach (ZipArchiveEntry archiveEntry in archive.Entries)
{
Console.WriteLine(“{0}\t {1} KB\t {2}\t {3} KB\t {4}\t”, archiveEntry.Name,
archiveEntry.Length / 1024,
archiveEntry.LastWriteTime.ToString(“dd-mm-yyyy hh:mm:ss”), archiveEntry.CompressedLength / 1024,
((double)archiveEntry.CompressedLength / archiveEntry.Length));
}
}
Refer the following MSDN BCL team blogs related the zip feature in .NET 4.5 BCL – http://blogs.msdn.com/b/bclteam/archive/tags/zip/
Happy Learning .NET 4.5 & VS 11!