我正在考虑使用 JSZip
在来自各种下游文件的文件上创建一个 zip 文件。这是我想要做的伪代码:
function* handler () {
const ids = this.request.body.ids;
const zip = new JSZip();
for (let i = 0; i < ids; i++) {
const r = yield request.get('/some/remote/service/' + ids[i]);
zip.file(ids[i], r.body);
}
this.body = zip.nodeStream():
}
但想必这将要求所有文件的内容同时存在于内存中,并且在下载所有文件之前不会开始流式传输。
我意识到我可以通过执行以下操作来优化下载时间:
const allFiles = yield ids.map((id) => request.get('/some/remote/service/' + id));
for (let i = 0; i < ids.length; i++) zip.file(ids[i], allFiles[i]);
但主要是我希望有一种方法可以一次只在内存中保存一个文件,并通过 zip 将结果流式传输回客户端。这可以用 JSZip
实现吗?
最佳答案
I'm hoping for a way to only hold one file in memory at a time and stream the result through zip back to the client. Is that possible with
JSZip
?
并非没有缺点。 JSZip 不接受 ( yet ) 生成器或函数作为文件内容。它需要文件的完整内容、文件的 promise 或流。这意味着您(还)无法在实际需要内容的最后一刻触发 API 调用。
当您添加流(使用 zip.file("filename.txt", myStream)
)时,JSZip 将暂停它并等待某些东西使用它(例如对 zip.generateNodeStream()
的调用或 getter)。
因此,您可以做的(在当前的 v3.1.2 中)限制内存使用量是将所有资源添加为流并调用 zip.generateNodeStream({streamFiles:true})
。主要缺点是,您确实打开了与 Web 服务的连接,并且在流式传输第一个文件时可能会遇到超时(比如在最后一个文件上)(或者更糟,取决于输入流处理 .pause()
的方式)。
关于streamFiles
以及问题的评论:zip 格式非常适合流媒体。正如 the documentation 中所述,streamFiles
选项决定 zip 文件内文件的 size/crc32 写入位置:数据之前(但我们需要暂时将文件保存在内存中以计算它们)或数据之后(流式传输所有内容,将计算值放在最后) )。
关于javascript - koa.js 中的 JSZip 具有流式输入/输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39213243/