Asp.Net Zip Multiple Files


This article is written by Pon Saravanan  on 06-Feb-11 Last modified on :06-Feb-11





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.

Screen Capture


 

Source Code

Markup(*.Aspx)


<%@ Page Language="vb" AutoEventWireup="false"
    CodeBehind="Default.aspx.vb" Inherits="ZipMultipleFiles._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:Button runat="server" ID="btnZipFiles" Text="Zip..." />
    </div>
    </form>
</body>
</html>

Code-Behind(*.Aspx.Vb)

Imports System.IO
Partial Public Class _Default
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, _
                    ByVal e As System.EventArgs) Handles Me.Load
    End Sub
    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)
        With FileZipper
            .AddFile(Server.MapPath(ResolveUrl("~/InputFiles/TextFile1.txt")))
            .AddFile(Server.MapPath(ResolveUrl("~/InputFiles/TextFile2.txt")))
            .AddFile(Server.MapPath(ResolveUrl("~/InputFiles/TextFile3.txt")))
            .Close()
        End With
        Response.Redirect("~/New.Zip")
        'ZipPackage()
    End Sub
End Class

Zipper Class (Zipper.vb)

Imports System.IO.Packaging
Imports System.IO
Public Class Zipper
    Private m_BufferSize As Integer?
    Private Zipped As Package
    Public Property BufferSize() As Integer?
        Get
            Return m_BufferSize
        End Get
        Set(ByVal value As Integer?)
            m_BufferSize = value
        End Set
    End Property
    Private m_ZipName As String
    Public Property ZipName() As String
        Get
            Return m_ZipName
        End Get
        Set(ByVal value As String)
            m_ZipName = value
        End Set
    End Property
    Public Sub New(ByVal ZipName As String, _
                   ByVal BufferSize As Integer)
        Me.ZipName = ZipName
        Me.BufferSize = BufferSize
    End Sub
    Public Sub New(ByVal ZipName As String)
        Me.ZipName = ZipName
        Me.BufferSize = 1024
    End Sub
    Public Sub Close()
        Zipped.Close()
    End Sub
    Public Sub AddFile(ByVal FilePath As String)
        If (String.IsNullOrEmpty(ZipName)) Then
            Throw New Exception("ZipName can not be empty")
            Return
        End If
        If (BufferSize Is Nothing) Then
            Throw New Exception("BufferSize can not be empty")
            Return
        End If
        If (Zipped Is Nothing) Then
            Zipped = Package.Open(ZipName, FileMode.OpenOrCreate)
        End If
        Dim ResolvedPath = ".\\" + Path.GetFileName(FilePath)
        Dim ResolvedUri = PackUriHelper.CreatePartUri( _
                            New Uri(ResolvedPath, UriKind.Relative))
        If (Zipped.PartExists(ResolvedUri)) Then
            Zipped.DeletePart(ResolvedUri)
        End If
        StuffFile(ResolvedUri, FilePath)
    End Sub
    Private Sub StuffFile(ByVal ResolvedUri As Uri, _
                          ByVal FilePath As String)
        Using FileData = New FileStream(FilePath, _
                                        FileMode.Open, _
                                        FileAccess.Read)
            Dim PartPackaged = Zipped.CreatePart(ResolvedUri, _
                                                 String.Empty, _
                                                 CompressionOption.Normal)
            Using FileDataStream = PartPackaged.GetStream
                Dim CalculatedBufferSize = 0
                If (BufferSize > FileDataStream.Length) Then
                    CalculatedBufferSize = FileDataStream.Length
                Else
                    CalculatedBufferSize = BufferSize
                End If
                Dim ActualBuffer(CalculatedBufferSize) As Byte
                Dim RedBytes = 0
                Dim WrittenBytes = 0
                Do
                    RedBytes = FileData.Read(ActualBuffer, _
                                             0, ActualBuffer.Length)
                    FileDataStream.Write(ActualBuffer, 0, RedBytes)
                    WrittenBytes += CalculatedBufferSize
                Loop While RedBytes > 0
            End Using
        End Using
    End Sub
End Class











Comments

Comments
   
Captcha Image
For you specially:  
Captcha Text Enter the text in the image.(Not Case sensitive)    



Spam Bot Trap



   



Select Theme
White
Blue
Brown
Gray