Потоковая передача zip-файла по протоколу http в .net с помощью SharpZipLib
Вопрос
Я создаю простой сервис загрузки, чтобы пользователь мог загружать все свои изображения с нашего сайта.Чтобы сделать это, я просто заархивирую все в http-поток.
Однако, похоже, все хранится в памяти, и данные не отправляются до тех пор, пока zip-файл не будет завершен и вывод закрыт.Я хочу, чтобы служба начала отправку сразу и не использовала слишком много памяти.
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();
}
Я вижу, как память рабочего процесса увеличивается, пока он создает файл, а затем освобождает память по завершении отправки.Как мне это сделать, не используя слишком много памяти?
Решение
Отключите буферизацию ответов с помощью context.Response.BufferOutput = false;
и удалите вызов Flush
из конца вашего кода.
Другие советы
use Response.BufferOutput = false; при запуске ProcessRequest и сбросить ответ после каждого файла.
К твоему сведению.Это рабочий код для рекурсивного добавления всего дерева файлов с потоковой передачей в браузер:
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();