【发布时间】:2013-11-29 20:14:40
【问题描述】:
我正在尝试即时创建任意大小的 zip 文件。 zip 存档的来源是一堆 URL,可能很大(列表中有 500 个 4MB JPG)。我希望能够在请求中执行所有操作,并立即开始下载,并在构建时创建和流式传输 zip。它不必驻留在内存或服务器的磁盘上。
我最接近的是: 注意:urls 是指向文件名的 URL 的键值对,因为它们应该存在于创建的 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();
这段代码给了我一个 zip 文件,但 zip 中的每个 JPG 文件都只是一个文本文件,上面写着“System.Net.ConnectStream”,我对此还有其他尝试,可以构建一个包含适当文件的 zip 文件,但是您可以通过一开始的延迟来判断服务器正在完全在内存中构建 zip,然后在最后将其炸毁。当文件数接近 50 时,它根本没有响应。 cmets 中的部分给我的结果与我尝试过 Ionic.Zip 的结果相同。
这是 IIS8 上的 .NET 4.5。我正在使用 VS2013 构建并尝试在 AWS Elastic Beanstalk 上运行它。
【问题讨论】:
-
StreamWriter版本不起作用,因为对streamWriter.Write的调用最终会在客户端流上调用ToString(),它解析为Object.ToString(),并且只写入类名。我真的不能说为什么CopyTo版本不起作用。您确定会创建与StreamWriter版本相同的 zip 文件吗? -
如果我将
memoryStream.WriteTo(Response.OutputStream)部分移动到foreach循环中并添加Response.Flush(),它似乎会立即开始流式传输(第一场战斗获胜),但生成的zip 文件比它大得多应该。我最好的猜测是他们WriteTo()调用正在写入整个流,所以 zip 文件是 (file1)+(file1+file2)+(file1+file2+file3) 等。Write()不会直接转到 @ 987654333@.