Package multiple files using Asp.Net Zip
Microsoft.Net has a very good utility for zipping aka packaging files. While there are good utilities there in open source/Code Plex for packaging files. I would still prefer to write the code using native functions and classes available in .Net. In this article I am going to use the System.IO.Packaging for showing how to attach multiple files into a zip.
Zipper class for Packaging
I have created a separate class called as Zipper for the future works as it gives great re-usability. This class can be used for the WinForms, WPF, or ASP.Net applications. Though has to be changed as per the specific needs. It is just a starter for writing more functions into the zipper class.
Referencing required assemblies
The System.IO.Packaging library is not directly available in the default set of references. You have to add a reference to the assembly known as windowsbase.dll under Program Files. In my system it is located right at C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll. Once it is referenced the namespace can be imported in the top of the class as Imports System.IO.Packaging.
Zipper Class and the properties
I have created two properties named as BufferSize and ZipName for specifieng the buffer size(I used 8192 in sample) and zip file path respectively. I have created two constructors and used BufferSize as 1024 if not specified.
Adding Multiple Files
This once an object for the zipper class is created that object can be used to add new files. And once done the handle has to be closed by calling the close() method. Class will not reopen the zipper for adding more files.
If you are adding the same file again the zipper will remove the existing one in the zip and add again.
Adding Files into Zip
The key to add a file into the zip is creating a part in the package. This can be done by calling the CreatePart method in the Package object we have created. Using this Part we can get access to the stream by calling GetStream() method. Use the stream to write the data. Once written the file is already embedded into the given package object.
Improvements for ASP.Net
I am planning to develop a class to read the binary values (images) from db to package to a zip file. And also the files can be directly served to response via a http handler without writing the files to disk. I hope it will be neat and clean.
<%@ Page Language="vb" AutoEventWireup="false"
CodeBehind="Default.aspx.vb" Inherits="ZipMultipleFiles._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml" >
<form id="form1" runat="server">
<asp:Button runat="server" ID="btnZipFiles" Text="Zip..." />
Partial Public Class _Default
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
Private Sub btnZipFiles_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles btnZipFiles.Click
Dim ZipFilePath = Server.MapPath("~/New.Zip")
If (File.Exists(ZipFilePath)) Then File.Delete(ZipFilePath)
Dim FileZipper As New Zipper(ZipFilePath, 8192)
Zipper Class (Zipper.vb)
Public Class Zipper
Private m_BufferSize As Integer?
Private Zipped As Package
Public Property BufferSize() As Integer?
Set(ByVal value As Integer?)
m_BufferSize = value
Private m_ZipName As String
Public Property ZipName() As String
Set(ByVal value As String)
m_ZipName = value
Public Sub New(ByVal ZipName As String, _
ByVal BufferSize As Integer)
Me.ZipName = ZipName
Me.BufferSize = BufferSize
Public Sub New(ByVal ZipName As String)
Me.ZipName = ZipName
Me.BufferSize = 1024
Public Sub Close()
Public Sub AddFile(ByVal FilePath As String)
If (String.IsNullOrEmpty(ZipName)) Then
Throw New Exception("ZipName can not be empty")
If (BufferSize Is Nothing) Then
Throw New Exception("BufferSize can not be empty")
If (Zipped Is Nothing) Then
Zipped = Package.Open(ZipName, FileMode.OpenOrCreate)
Dim ResolvedPath = ".\\" + Path.GetFileName(FilePath)
Dim ResolvedUri = PackUriHelper.CreatePartUri( _
New Uri(ResolvedPath, UriKind.Relative))
If (Zipped.PartExists(ResolvedUri)) Then
Private Sub StuffFile(ByVal ResolvedUri As Uri, _
ByVal FilePath As String)
Using FileData = New FileStream(FilePath, _
Dim PartPackaged = Zipped.CreatePart(ResolvedUri, _
Using FileDataStream = PartPackaged.GetStream
Dim CalculatedBufferSize = 0
If (BufferSize > FileDataStream.Length) Then
CalculatedBufferSize = FileDataStream.Length
CalculatedBufferSize = BufferSize
Dim ActualBuffer(CalculatedBufferSize) As Byte
Dim RedBytes = 0
Dim WrittenBytes = 0
RedBytes = FileData.Read(ActualBuffer, _
FileDataStream.Write(ActualBuffer, 0, RedBytes)
WrittenBytes += CalculatedBufferSize
Loop While RedBytes > 0