在ASP.NET中将大文件写入HttpResponse的最有效方法

时间:2011-04-28 23:01:32

标签: c# .net asp.net streaming

我正在创建一个ZIP文件。我正在使用dotnetzip来执行此操作。 我的ZIP文件大小最多可达500 MB,许多用户同时尝试下载它。

我提供文件的最有效方式是什么?如果给出了选择,我宁愿不将文件保存在磁盘上,因为这可能会导致严重的磁盘空间限制。

编辑:有关我的用例的更多信息:

我们将文件托管在Intranet网站中托管的SharePoint 2010资产库中,该网站遍布全球。文件通常为10-80 MB。用户希望能够一次下载多个文件。

2 个答案:

答案 0 :(得分:2)

嗯,理论上

对于传统的ASP.Net应用程序,您应该只能将响应数据(字节)写入HttpContext.Response.OutputStream(如何获取http响应上下文将取决于您如何处理下载请求,例如,如果您正在实现IHttpHandler然后你得到传递给你的http上下文。)

看看DotNetZip示例,Save方法看起来像一个流,所以这就像

一样简单
zip.Save(context.Response.OutputStream);

如果zip文件被许多用户重复使用和下载,那么您可以在创建zip时将zip写入MemoryStream,以便稍后将此内存流的内容复制到各个响应中:

MemoryStream stream = new MemoryStream()
zip.Save(stream);
// Save data somewhere common (e.g. cache it)
byte[] data = stream.ToArray();

将此数据写回响应:

MemoryStream reader = new MemoryStream(data);
CopyStream(reader, context.Response.OutputStream);

有关CopyStream的实现,请参阅Best way to copy between two Stream instances - C#

然而在现实中

考虑到这一点,这意味着如果zip文件是500MB,我们在内存中存储500MB的数据 - 如果这是唯一存在的zip文件但是如果有3或4个这些我们很快就会耗尽“内存”(即虚拟地址空间)。

解决方案?我担心最简单的方法是将zip保存到文件中(即使它是一个不是由IIS直接提供的临时文件)而不是内存流:

// To save the zip
string filename = Path.GetTempFileName();
zip.Save(filename);

// To write the file
context.Response.TransmitFile(filename);

完成后,您也应该删除该文件。

请注意,如果您决定在多个用户之间共享相同的zip,则只需要打扰它 - 如果您只是按用户构建zip并使用{{1}将其直接写入输出流那么事情就不那么麻烦了。我的建议是首先以简单的方式进行操作然后进行测试,看看是否只能通过创建一次zip来解决性能问题。

答案 1 :(得分:1)

为此,您可能会通过使用消息队列异步执行此操作。这样,压缩就会添加到队列中,您可以让一台服务器执行此操作,也可以使用多台服务器。我不知道这是否符合您的要求。

我之前使用过Rabbit MQ(http://www.rabbitmq.com/)。