Dot Net Tricks

Articles about .NET, ASP.NET, C#, Object Oriented Programming and Agile Methodologies
Welcome to Dot Net Tricks Sign in | Join | Help
in Search

Software Theosophy

Zip It Good - Creating Zip Files on the fly using ASP.NET and C#

The other day, I had an interesting programming problem.  I had a series of files in a website, and I needed to give the user the option of downloading them all at once.  I didn’t want to have create each of them one by one by hand.  Even if I created the zip archive programmatically, I didn’t want to leave the zip file on the file sytem.  I wanted to make sure the compressed version did not get out of date and I wanted to avoid taking up unnecessary space on the hard drive.  I thought about using the zip library that is part of J#, but I wasn’t sure if I would have to run the install program to get the J# distributable on my development and production servers.  That seemed like a hassle.  So instead I found SharpZipLib, which is a component to create zip files written in .NET.  My code is a variation of some example code for creating the files on fly, except with my version, I never save them to the file system.  Instead, I create the archive in memory and streame it directly to the browser.  I’ll attach the full source code, but here is the gist of what I did.

 

First, I retrieve the files that I need from the file system.  Next, I instantiate standard .NET MemoryStream object.  The MemoryStream lets me create a binary representation of the files in memory.  I pass the MemoryStream into the SharpZipLib’s ZipOutputStream object, which represents a zip file:

 

string[] filesToZip = Directory.GetFiles(Server.MapPath("~/filestozip/"));

 

this.memoryStream = new MemoryStream();

ZipOutputStream zipStream = new ZipOutputStream(this.memoryStream);

 

After this, I create a ZipEntry object for each file that I want to put in the archive and populate it with any header information:

 

string fileName = Path.GetFileName(filesToZipIdea [I]);

ZipEntry entry = new ZipEntry(fileName);

entry.DateTime = DateTime.Now;

 

Then I read in each of the files in as a FileStream in the standard fashion.  (By the way, I hate streams for some reason.   I can never remember how they are supposed to be nested, which ones are abstract and which ones are concrete, and how to use the buffer, etc.  But I digress…)  After the file is read from the stream it is placed into the ZipEntry object, which in turn is written into the ZipOutputStream:

 

using (FileStream fileStream = File.OpenRead(filesToZipIdea [I]) )

{

 

      byte[] buffer = new byte[fileStream.Length];

      fileStream.Read(buffer, 0, buffer.Length);

 

      entry.Size = fileStream.Length;

      fileStream.Close();

 

      crc.Reset();

      crc.Update(buffer);

      entry.Crc = crc.Value;

 

      zipStream.PutNextEntry(entry);

      zipStream.Write(buffer, 0, buffer.Length);

}

 

zipStream.Finish();

 

In the original code example I read, the stream was saved to disk, then closed.  I found that closing the stream meant I couldn’t do anything else with it.  Instead, I keep it open so I can send it back to the browser, in the same way you would send a file stream.  This code should look pretty familiar to most ASP.NET developers who have generated an excel file, PDF, image, etc and sent it to the browser programmatically:

 

Response.Clear();

Response.AddHeader("Content-Type", "binary/octet-stream");

Response.AddHeader("Content-Length", zip.Length.ToString());

 

//the filename might be dynamic as well.

Response.AddHeader("Content-Disposition",

       "attachment; filename=YourZipFile.zip; size="

       + zip.Length.ToString());

Response.Flush();

 

Response.BinaryWrite(this.memoryStream.ToArray());

 

Response.Flush();

Response.End();

 

Finally, I close and dispose the memory stream.  I’m not sure if both are necessary.  Usually, Dispose will call Close in most objects (such as DataReaders) but you can’t count on it.

 

this.memoryStream.Close();

this.memoryStream.Dispose();

 

That’s it.  Below are the links to the SharpZipLib, the original post that I based my code off of, and the download to the full source of this example.

 

Full Source Code

 http://dotnettricks.com/files/4/snippets/entry95.aspx

 

SharpZipLib

http://www.icsharpcode.net/OpenSource/SharpZipLib/

 

Creating Zip Files on the Fly

http://weblogs.asp.net/dneimke/archive/2005/02/25/380273.aspx

 

Published Saturday, September 02, 2006 12:02 AM by Fregas
Filed Under:

Comments

 

pinguin said:

Great, but what about memory foot? Your code loads files to memory. Sometimes is necessary to send large files zipped.. how to send zipped files without memory using?
March 22, 2007 10:57 AM
 

Giatas said:

Nice!
March 28, 2007 2:48 PM
Anonymous comments are disabled

About Fregas

Craig is currently the Lead Developer in Fort Worth, Texas for Enilon Group, a web development firm. He has been programming since 3rd grade (using the Commodoore PET) and professionally for the past 7 years. He has written several articles for ASPToday.com and co-authored the book "Beginning Web Programming using VB.NET and Visual Studio .NET" Currently, his favorite programming language is C#, but he has programmed in Visual Basic, T-SQL, Ruby, ColdFusion, ASP 3.0/VBScript, ASP.NET, Javascript, Java and even Pascal. Besides programming, Craig is best known for his cooking and his somewhat offbeat sense of humor.

This Blog

Post Calendar

<September 2006>
SuMoTuWeThFrSa
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

Syndication

Powered by Community Server, by Telligent Systems