我有一个下载1GB文件的XHR对象。
function getFile(callback)
{
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status == 200) {
callback.apply(xhr);
}else{
console.log("Request error: " + xhr.statusText);
}
};
xhr.open('GET', 'download', true);
xhr.onprogress = updateProgress;
xhr.responseType = "arraybuffer";
xhr.send();
}
但File API无法将所有内容加载到内存中,即使是来自worker也是如此 它会失去记忆......
btn.addEventListener('click', function() {
getFile(function() {
var worker = new Worker("js/saving.worker.js");
worker.onmessage = function(e) {
saveAs(e.data); // FileSaver.js it creates URL from blob... but its too large
};
worker.postMessage(this.response);
});
});
Web Worker
onmessage = function (e) {
var view = new DataView(e.data, 0);
var file = new File([view], 'file.zip', {type: "application/zip"});
postMessage('file');
};
我不是要压缩文件,这个文件已经从服务器压缩了。
我认为首先将它存储在indexedDB上,但我还是必须加载blob或文件,即使我按范围字节请求,很快或者很晚我将不得不构建这个巨大的blob ..
我想创建blob:url并在浏览器下载后将其发送给用户
我将使用FileSystem API for Google Chrome,但我想为firefox制作一些内容,我查看了File Handle Api,但没有...
我是否必须为firefox构建扩展,以便像FileSystem那样为google chrome做同样的事情?
Ubuntu 32位
答案 0 :(得分:6)
使用ajax加载1gb +不方便仅用于监控下载进度和填满内存。
相反,我只是发送带有Content-Disposition
标题的文件来保存文件。
但是有一些方法可以绕过它来监控进度。选项一是有一个第二个websocket,它指示你在正常下载获取请求时已经下载了多少。另一个选项将在后面的
中描述我知道你在谈话中谈到过使用Blinks沙盒文件系统。但它有一些缺点。如果使用持久存储,可能需要权限。它只允许剩余20%的可用磁盘。如果chrome需要释放一些空间,那么它将丢弃最后用于最新文件的任何其他域临时存储。除此之外不能在私人模式下工作 更不用说它已经放弃了对它的支持,并且可能永远不会在其他浏览器中结束 - 但它们很可能不会删除它,因为许多站点仍然依赖它
处理这个大文件的唯一方法是使用流。这就是我创建StreamSaver的原因。这只能在Blink(chrome& opera)ATM中使用,但最终将得到其他浏览器的支持,并将whatwg规范备份为标准。
fetch(url).then(res => {
// One idea is to get the filename from Content-Disposition header...
const size = ~~res.headers.get('Content-Length')
const fileStream = streamSaver.createWriteStream('filename.zip', size)
const writeStream = fileStream.getWriter()
// Later you will be able to just simply do
// res.body.pipeTo(fileStream)
// instead of pumping
const reader = res.body.getReader()
const pump = () => reader.read()
.then(({ value, done }) => {
// here you know how large the value (chunk) is and you can
// figure out the download speed/progress when comparing it to the size
return done
? writeStream.close()
: writeStream.write(value).then(pump)
)
// Start the reader
pump().then(() =>
console.log('Closed the stream, Done writing')
)
})
这不会占用任何内存
答案 1 :(得分:4)
我有一个理论,即如果您将文件拆分为块并将它们存储在indexedDB中,然后将它们合并在一起它将起作用
blob不是由数据构成的...它更像是指向文件可以从哪里读取的指针
这意味着你将它们存储在indexedDB中然后做这样的事情(使用FileSaver或替代)
finalBlob = new Blob([blob_A_fromDB, blob_B_fromDB])
saveAs(finalBlob, 'filename.zip')
但是我无法证实这一点,因为我还没有对它进行过测试,如果有其他人能够做到这一点会很好