似乎有一个用于在客户端进行压缩的包JSZip。请注意,您需要 Downloadify 才能在用户计算机上创建文件。不过,它看起来不太支持跨浏览器,而且您在客户端的 JS 中抛出的数据量可能会导致问题。
除了发送 zip 文件,您可以查看流式传输不同的存档格式,例如TAR 文件或ISO 文件吗?它将只包含有关文件的元数据,然后是文件数据。
或者,您可以借用 7digital 和 Bleep 唱片音乐商店使用的解决方案,即将服务器上的文件压缩到临时目录,同时立即向用户呈现页面。该页面使用客户端的一段JS轮询服务器,直到整个文件准备好下载,然后它可以正常开始下载。
更新
我注意到,如果您从 DropBox 网站下载目录,它会立即开始下载并且不知道完整的文件大小 - 这表明它在完成创建存档之前开始下载。对zip 文件格式和DEFLATE 算法的进一步阅读表明,您可以在从服务获得完整文件数据之前开始生成压缩数据并将其流式传输到客户端。
该代码类似于以下未经测试和简化的示例:(使用DotNetZip类名)
// Get a stream to the client
using (var zipStream = ZipOutputStream(Response.OutputStream)) {
foreach (var filename in filenames) {
// Write file header
ZipEntry entry = new ZipEntry(filename);
zipStream.PutNextEntry(entry);
// Write file chunks
byte[] chunk;
while ((chunk = service.GetChunk(filename)).Length > 0) {
zipStream.Write(chunk, 0, chunk.Length);
}
}
// Write zip file directory to complete file
zipStream.Finish();
}
如果您希望文件被进一步压缩(如果您给压缩器提供更大的块可能会出现这种情况),但还希望数据流尽快进行,并且您知道数据从服务到应用程序的速度比它去的快从您的应用程序到您的客户端,您可以在 foreach 循环中实现某种指数缓冲区。
int chunksPerWrite = 1; // Better if this is defined outside of the foreach loop
byte[] chunk;
var chunks = new List<byte[]>();
while ((chunk = service.GetChunk(filename)).Length > 0) {
chunks.Add(chunk)
if (chunks.Count >= chunksPerWrite) {
// Combine all the chunks with some array copying logic not included
byte[] megaChunk = CombineAllChunks(chunks);
zipStream.Write(megaChunk, 0, megaChunk.Length);
chunksPerWrite *= 2; // or chunksPerWrite++ for a linear growth
}
}
// Cut for brevity - combine any last chunks and send to the zipStream.
我对 ZIP 规范的阅读表明,一次可以有效压缩多少数据是有限制的,但我无法弄清楚这个限制是什么(它可能取决于数据?)。我很想听听任何更了解规范的人...
如果您发现出于某种原因需要自己滚动,Zip 文件也有一个没有压缩引擎的普通存储机制,如果您不担心带宽,它会更容易。