Transmisión de un archivo zip a través de http en .net con SharpZipLib
Pregunta
Estoy creando un servicio de descarga simple para que un usuario pueda descargar todas sus imágenes desde el sitio. Para hacer eso, simplemente comprimo todo en la secuencia http.
Sin embargo, parece que todo está almacenado en la memoria, y los datos no se envían hasta que se completa el archivo zip y se cierra la salida. Quiero que el servicio comience a enviarse a la vez y no use demasiada memoria.
public void ProcessRequest(HttpContext context)
{
List<string> fileNames = GetFileNames();
context.Response.ContentType = "application/x-zip-compressed";
context.Response.AppendHeader("content-disposition", "attachment; filename=files.zip");
context.Response.ContentEncoding = Encoding.Default;
context.Response.Charset = "";
byte[] buffer = new byte[1024 * 8];
using (ICSharpCode.SharpZipLib.Zip.ZipOutputStream zipOutput = new ICSharpCode.SharpZipLib.Zip.ZipOutputStream(context.Response.OutputStream))
{
foreach (string fileName in fileNames)
{
ICSharpCode.SharpZipLib.Zip.ZipEntry zipEntry = new ICSharpCode.SharpZipLib.Zip.ZipEntry(fileName);
zipOutput.PutNextEntry(zipEntry);
using (var fread = System.IO.File.OpenRead(fileName))
{
ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(fread, zipOutput, buffer);
}
}
zipOutput.Finish();
}
context.Response.Flush();
context.Response.End();
}
Puedo ver el crecimiento de la memoria del proceso de trabajo mientras se crea el archivo, y luego libera la memoria cuando se realiza el envío. ¿Cómo hago esto sin usar demasiada memoria?
Solución
Deshabilitar el búfer de respuesta con Flush
del final de tu código.
Otros consejos
use Response.BufferOutput = false; al inicio de ProcessRequest y vaciar la respuesta después de cada archivo.
Para tu información. Este es un código de trabajo para agregar recursivamente un árbol completo de archivos, con transmisión al navegador:
string path = @"c:\files";
Response.Clear();
Response.ContentType = "application/zip";
Response.AddHeader("Content-Disposition", string.Format("attachment; filename=\"{0}\"", "hive.zip"));
Response.BufferOutput = false;
byte[] buffer = new byte[1024 * 1024];
using (ZipOutputStream zo = new ZipOutputStream(Response.OutputStream, 1024 * 1024)) {
zo.SetLevel(0);
DirectoryInfo di = new DirectoryInfo(path);
foreach (string file in Directory.GetFiles(di.FullName, "*.*", SearchOption.AllDirectories)) {
string folder = Path.GetDirectoryName(file);
if (folder.Length > di.FullName.Length) {
folder = folder.Substring(di.FullName.Length).Trim('\\') + @"\";
} else {
folder = string.Empty;
}
zo.PutNextEntry(new ZipEntry(folder + Path.GetFileName(file)));
using (FileStream fs = File.OpenRead(file)) {
ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(fs, zo, buffer);
}
zo.Flush();
Response.Flush();
}
zo.Finish();
}
Response.Flush();