I am trying to create a zip file of any size on the fly. The source of the zip archive is a bunch of URLs and could be potentially large (500 4MB JPGs in the list). I want to be able to do everything inside the request and have the download start right away and have the zip created and streamed as it is built. It should not have to reside in memory or on disk on the server.
The closest I have come is this: Note: urls is a keyvaluepair of URLs to the file names as they should exist in the created zip
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/zip";
Response.AddHeader("Content-Disposition", "attachment; filename=DyanmicZipFile.zip");
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
foreach (KeyValuePair<string, string> fileNamePair in urls)
{
var zipEntry = archive.CreateEntry(fileNamePair.Key);
using (var entryStream = zipEntry.Open())
using (WebClient wc = new WebClient())
wc.OpenRead(GetUrlForEntryName(fileNamePair.Key)).CopyTo(entryStream);
//this doesn't work either
//using (var streamWriter = new StreamWriter(entryStream))
// using (WebClient wc = new WebClient())
// streamWriter.Write(wc.OpenRead(GetUrlForEntryName(fileNamePair.Key)));
}
}
memoryStream.WriteTo(Response.OutputStream);
}
HttpContext.Current.ApplicationInstance.CompleteRequest();
This code gives me a zip file, but each JPG file inside the zip is just a text file that says "System.Net.ConnectStream" I have other attempts on this that do build a zip file with the proper files inside, but you can tell by the delay at the beginning that the server is completely building the zip in memory and then blasting it down at the end. It doesn't respond at all when the file count gets near 50. The part in comments gives me the same result I have tried Ionic.Zip as well.
This is .NET 4.5 on IIS8. I am building with VS2013 and trying to run this on AWS Elastic Beanstalk.
So to answer my own question - here is the solution that works for me:
private void ProcessWithSharpZipLib()
{
byte[] buffer = new byte[4096];
ICSharpCode.SharpZipLib.Zip.ZipOutputStream zipOutputStream = new ICSharpCode.SharpZipLib.Zip.ZipOutputStream(Response.OutputStream);
zipOutputStream.SetLevel(0); //0-9, 9 being the highest level of compression
zipOutputStream.UseZip64 = ICSharpCode.SharpZipLib.Zip.UseZip64.Off;
foreach (KeyValuePair<string, string> fileNamePair in urls)
{
using (WebClient wc = new WebClient())
{
using (Stream wcStream = wc.OpenRead(GetUrlForEntryName(fileNamePair.Key)))
{
ICSharpCode.SharpZipLib.Zip.ZipEntry entry = new ICSharpCode.SharpZipLib.Zip.ZipEntry(ICSharpCode.SharpZipLib.Zip.ZipEntry.CleanName(fileNamePair.Key));
zipOutputStream.PutNextEntry(entry);
int count = wcStream.Read(buffer, 0, buffer.Length);
while (count > 0)
{
zipOutputStream.Write(buffer, 0, count);
count = wcStream.Read(buffer, 0, buffer.Length);
if (!Response.IsClientConnected)
{
break;
}
Response.Flush();
}
}
}
}
zipOutputStream.Close();
Response.Flush();
Response.End();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With