在客户端使用巨大的JavaScript HTML5 blob(从大型ArrayBuffers中获取)构建一个巨大的文件

20
我正在编写一个Web浏览器应用程序(客户端),该应用程序从多个位置下载大量数据块并将它们合并以构建Blob。然后,将该Blob保存到本地文件系统中作为普通文件。我使用ArrayBuffer对象和blob来完成这项工作。
对于小型和中型文件(大约700 MB),这种方式可以正常工作,但是使用更大的文件时浏览器会崩溃。由于RAM内存有其限制,因此我需要构建Blob以生成文件,但我想允许用户下载比该大小大得多的文件(例如,大约8GB的文件)。
如何构建Blob避免大小限制?LocalStorage比RAM内存更受限制,因此我不知道该使用什么或如何做到这一点。

1
创建文件并尝试将所有传入的数组附加到文件中,而不仅仅是写入一次。 - Khamidulla
1个回答

8

看起来你只是简单地将数据数组串联在一起?为什么不通过一个巨大的 blob 来追加 array-buffers 呢?你需要逐个迭代和追加每个 arrayBuffer。你可以使用 seek 到文件写入器的末尾去追加数组。如果只想读取你的巨大 blob 的某些部分,你可以获取 blob 的 slice 以避免浏览器崩溃。

追加函数

function appendToFile(fPath,data,callback){
    fs.root.getFile(fPath, {
        create: false
    }, function(fileEntry) {
        fileEntry.createWriter(function(writer) {
            writer.onwriteend = function(e) {
                callback();
            };
            writer.seek(writer.length);
            var blob = new Blob([data]);
            writer.write(blob);
        }, errorHandler);
    }, errorHandler);
}

为了避免读取整个大型blob,只有在生成您提到的文件时才阅读部分/块。

部分读取功能

function getPartialBlobFromFile(fPath,start,stop,callback){
    fs.root.getFile(fPath, {
        creation:false
    }, function(fileEntry){
        fileEntry.file(function(file){
            var reader = new FileReader();
            reader.onloadend = function(evt){
                if(evt.target.readyState == FileReader.DONE){
                    callback(evt.target.result);
                }
            };
            stop = Math.min(stop,file.size);
            reader.readAsArrayBuffer(file.slice(start,stop));
        }, errorHandler)
    }, errorHandler);
}

您可能需要保留索引,例如在您的大型二进制大对象(BLOB)的标题部分中 - 在我能够给出更精确的反馈之前,我需要了解更多信息。

更新 - 避免配额限制,临时存储与持久存储 回应下面的评论
看起来您正在使用临时存储而遇到了存储配额问题。以下是从 Google 找到的一段摘录(点击这里)

临时存储被所有运行在浏览器中的 Web 应用程序共享。共享池可以达到可用磁盘空间的一半。已被应用程序使用的存储也包括在共享池的计算中;就是说,计算是基于(可用存储空间 + 应用正在使用的存储)* .5。

每个应用程序最多可以拥有共享池的 20%。例如,如果总可用磁盘空间为 50 GB,则共享池为 25 GB,并且应用程序最多可以拥有 5 GB。这是从可用磁盘空间(50 GB)的一半(最多 25 GB)的 20%(最多 5 GB)计算而来的。

要避免此限制,您需要切换到持久存储,它将允许您配额与磁盘上可用的空闲空间一样多。为此,请使用以下方法初始化文件系统,而不是使用临时存储请求。

navigator.webkitPersistentStorage.requestQuota(1024*1024*5, 
  function(gB){
  window.requestFileSystem(PERSISTENT, gB, onInitFs, errorHandler);
}, function(e){
  console.log('Error', e);
})

现在我有另一个问题:这将一个文件构建到浏览器的HTML5文件系统中,但该存储空间是有限的(虽然我请求了5GB,但浏览器只允许我使用约2GB),因此我在处理比它更大的文件时会遇到问题。有没有办法去除这些限制? - sgmonda
也许,你是怎么发现这个问题的?有没有抛出错误或其他信息?你的硬盘有多大/可用空间有多少?我很感兴趣。如果你正在使用Chrome,这可能是最近Chrome更新的垃圾回收问题。我不得不设置超时并重试Ajax下载。让我知道,我会在回到桌面时尝试帮助你。 - Arthur Weborg
我使用 window.requestFileSystem() 请求5GB的临时存储空间,但是如果我调用 navigator.webkitTemporaryStorage.queryUsageAndQuota(),我会发现只有2GB(或在其他计算机上更少)可供我使用。 - sgmonda
1
啊,原来你正在使用临时存储?你可以通过使用持久存储来避免这个问题。临时存储仅允许使用剩余未使用驱动器空间的共享池的20%。阅读此链接以获取更多信息。你需要切换到持久存储,以下是我用代码编写的答案,说明了如何做到这一点persistent query。持久存储允许您使用所有未使用的磁盘空间(但用户必须接受浏览器提供的弹出请求)。 - Arthur Weborg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接