Since the release of the .Net Framework 3.0, we are now able to handle .zip files. For sure it is an interesting feature because the .zip format is surely the most used compression format. Microsoft provides the System.IO.Packaging class but it is so deeply hidden that most of us missed it.
This new class suffers serious limitations. So read on before you start digging yourself into it.
This is my first article that specifically targets the .Net framework 3.0 and above. To create this demo application, I have used Visual Basic 2008 but you could do it with Visual Basic 2005 if you have installed the .Net Framework 3.0.
Setting the reference
When I learned the existence of the System.IO.Packaging class, I first opened the reference dialog to find a component named something like System.IO.Packaging (admit that it would have make sense since it is the name of the class) and I couldn’t find it.
Because I didn’t find anything close to that, I started to doubt that this class really existed. After spending some time googling around, I found that you need to add a reference to the “WindowBase” component as shown in figure 1.
Figure 1: Setting the reference
The operation is not really straight-forward, you cannot simply call a Zip method. That would have been to easy!
The first thing you need to do is to open a Package (you will find this code in the click event handler of the btnZip control):
Dim objZip As Package = ZipPackage.Open(kZipFile, FileMode.OpenOrCreate, FileAccess.ReadWrite)
Once you have the package opened, you can start adding file to your package (you will also find this code in the click event handler of the btnZip control):
AddFileToZip(objZip, IO.Path.Combine(Application.StartupPath, "Test1.txt"))
Private Sub AddFileToZip(ByVal pZip As Package, ByVal pFileToAdd As String)
'Validate if the file exists
If Not File.Exists(pFileToAdd) Then
Throw New FileNotFoundException("AddFileToZip cannot process file " + pFileToAdd)
'Create a URI from the filename to zip (to ensure the name is valid)
Dim partURI As New Uri(CreateUriFromFilename(pFileToAdd), UriKind.Relative)
'Create a Package Part
Dim pkgPart As PackagePart = pZip.CreatePart(partURI, _
'Read the file into a byte array
Dim arrBuffer As Byte() = File.ReadAllBytes(pFileToAdd)
'Add the array of byte to the Package
pkgPart.GetStream().Write(arrBuffer, 0, arrBuffer.Length)
A first limitation I see here is the performance of this process on very large files. And don’t even think on trying to zip petabytes with this method because it will bomb. The Length property of the array is of type Int32. I could have used the LongLength property instead which is of type Int64.
The first test
You are now ready to do a first test and see some results. My demo application zips 2 text files that are in the debug folder. The resulting file is sent to the C:\Temp folder and is name MyZipTestFile.zip. When opening it with WinZip (or any other application that can handle that kind of file), you will discover another surprise: a file named [Content_Types].xml (see figure 2).
Figure 2: The content of the zip file
Figure 3: Content of the “magic” file
Now that we have zipped files, it would surely be helpful to unzip them.
The click event handler of the btnUnzip control does some validation to ensure that the zip file exists and also that the output folder (where files will get extracted) exists (otherwise it is automatically created for you). This output folder is named Test in your debug folder. After those validations, the ExtractFromZip method is called.
This method reads like this:
Private Sub ExtractFromZip(ByVal pZipFilename As String, ByVal pOutputPath As String)
Using pkgMain As Package = Package.Open(pZipFilename, FileMode.Open, FileAccess.Read)
For Each pkgPart As PackagePart In pkgMain.GetParts()
Dim strTarget As String = Path.Combine(pOutputPath, CreateFilenameFromUri(pkgPart.Uri))
Using stmSource As Stream = pkgPart.GetStream(FileMode.Open, FileAccess.Read)
Using stmDestination As Stream = File.OpenWrite(strTarget)
Dim arrBuffer(10000) As Byte
Dim intRead As Integer
intRead = stmSource.Read(arrBuffer, 0, arrBuffer.Length)
While intRead > 0
stmDestination.Write(arrBuffer, 0, intRead)
intRead = stmSource.Read(arrBuffer, 0, arrBuffer.Length)
The second test
Now run the application again and click the Unzip button.
The content of your zip file will be extracted into a folder called Test into the startup folder (probably the debug folder).
Discovering a serious limitation
So far, we have been able to create zip files and read them with Winzip (or any other compatible application) and unzip those files.
Now, find the zip file your application just created (probably in c:\temp) and add file to it. Now run the application again and click the Unzip button. Check the output folder (Test in the debug folder) and look carefully. Your newly added file is not there! For me this is a very serious limitation. That means that an application can zip files and extract from them but you will never be able to manually add files to the zip files.
But if you overwrite a file in your zip file and you extract from it, you will get the new content.
If you find that this implementation does not fit your needs, you have at least 2 other free libraries:
Notice that all libraries listed above are working for application using the .Net Framework 2.0.
I have heard that this class was basically developed to support Office 2007 files. For those who don’t already know the trick, rename a Office 2007 file (.docx, .xlsx, .pptx, ...) to .zip and double-click on it. You will then see all the xml files that are used.
The implementation is not complete and serious limitations exist. I would not recommend using this class and download another compression component.
I think it is the first time I tell you not to use one of the class but considering that the implementation is not complete, that serious limitations exist, and that free excellent alternatives are available, I really think I needed to tell you.