使用 SharpZipLib 在 .net 中通过 http 流式传输 zip 文件
Posted
技术标签:
【中文标题】使用 SharpZipLib 在 .net 中通过 http 流式传输 zip 文件【英文标题】:Streaming a zip file over http in .net with SharpZipLib 【发布时间】:2010-10-12 04:33:27 【问题描述】:我正在制作一个简单的下载服务,以便用户可以从外部站点下载他的所有图像。 为此,我只需将所有内容压缩到 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();
我可以看到工作进程在创建文件时内存在增长,然后在完成发送后释放内存。如何在不占用太多内存的情况下做到这一点?
【问题讨论】:
【参考方案1】:Disable response buffering 和 context.Response.BufferOutput = false;
并从代码末尾删除 Flush
调用。
【讨论】:
我相信还有其他方法可以处理非常大的文件,允许单独的请求获得单独的响应块。我会将文件压缩到磁盘上,以便能够在多个请求中提供它,而不必每次都重新压缩。【参考方案2】:使用 Response.BufferOutput = false;在 ProcessRequest 开始时并在每个文件之后刷新响应。
【讨论】:
缓冲关闭时,Flush 没有任何用处。【参考方案3】:仅供参考。这是递归添加整个文件树的工作代码,并流式传输到浏览器:
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();
【讨论】:
以上是关于使用 SharpZipLib 在 .net 中通过 http 流式传输 zip 文件的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Quartz.net 中通过 DI 使用添加的调度程序