如何在不使浏览器崩溃的情况下使用IndexedDB创建一个非常长的字符串?

31

我正在编写一个Web应用程序,它会生成一个潜在的大型文本文件供用户下载,并且所有处理都在浏览器中完成。到目前为止,我能够以小块读取超过1 GB的文件,处理每个块,逐步生成一个大输出文件,并在IndexedDB中存储不断增长的输出。我的更加天真的尝试是将所有结果保存在内存中,然后在最后一刻将它们序列化到文件中,这导致所有浏览器都崩溃了。

我的问题有两个方面:

  1. 我可以在没有先将整个条目读入内存的情况下向IndexedDB中的一个条目(字符串或数组)追加内容吗?现在,这样做:

    task.dbInputWriteQueue.push(output);
    var transaction = db.transaction("files", "readwrite");
    var objectStore = transaction.objectStore("files");
    var request = objectStore.get(file.id);
    request.onsuccess = function()
    {
        request.results += nextPartOfOutput
        objectStore.put(request.results);
    };
    

    当输出内容变得很大时,会导致崩溃。我可以将一堆小条目写入数据库,但是后来我仍然需要将它们全部读入内存才能连接它们。请参见我的问题的第二部分...

  2. 对于 IndexedDB 中的值,我是否可以创建一个数据对象 URL 来引用它,而不必将该值加载到内存中? 对于小字符串,我可以这样做:

    var url = window.URL.createObjectURL(new Blob([myString]), {type: 'text/plain'});
    

    但对于大字符串来说,这个方法就不太适用了。事实上,在字符串加载之前程序就会崩溃。似乎使用 IndexedDB 的 get() 进行大读取(即使是开发者工具)会导致至少 Chrome 崩溃。

如果我使用 Blob 而不是字符串,会更快吗?这个转换是否廉价?

基本上,我需要一种用 JavaScript 将一个非常大的文件写入磁盘而不必在任何时间点将整个文件加载到内存中的方法。我知道可以给 createObjectURL 传递一个 File,但在我的情况下,那并不起作用,因为我正在从用户提供的文件中生成一个文件。


2
在问题之中是否排除使用已被废弃的文件系统API? - Josh
4
嗨Matt,很抱歉告诉你在Chrome浏览器上只使用文件系统API是可以实现的,我已经实现了这样的解决方案,并且成功地创建了最多4GB的文件。另一个解决方案是将数据发送到服务器并在那里创建文件。在File API添加写入功能之前,浏览器中无法实现此功能。 - Deni Spasovski
2
正如@DeniSpasovski建议的那样,尝试“将数据发送到服务器并在那里创建文件”。此外,使用POST而不是GET进行发布,因为POST允许发送更多数据。 - Agi Hammerthief
1
另一个方向,如果你的目标只是桌面浏览器,可以考虑使用swf生成文件 - https://dev59.com/hl3Ua4cB1Zd3GeqP_Epr - Deni Spasovski
3
@AgiHammerthief 嗯...我要等那个1-4GB的上传;< - user2864740
显示剩余8条评论
2个回答

8

存储Blob将使用更少的空间和资源,因为不再需要转换为base64。您甚至可以将“text/plain”对象存储为Blobs:

var blob = new Blob(['blob object'], {type: 'text/plain'});
var store = db.transaction(['entries'], 'readwrite').objectStore('entries');

// Store the object  
var req = store.put(blob, 'blob');
req.onerror = function(e) {
    console.log(e);
};
req.onsuccess = function(event) {
    console.log('Successfully stored a blob as Blob.');
};

您可以在这里查看更多信息:https://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/ 自2014年夏季起,Chrome才开始支持此功能:http://updates.html5rocks.com/2014/07/Blob-support-for-IndexedDB-landed-on-Chrome-Dev,因此您无法在旧版本的Chrome上使用此功能。

2
在存储了约1GB的数据后,将文件存储在Blob中会出现问题。 - Deni Spasovski
我认为到目前为止,在不将文件加载到内存中的情况下,你无法在js中放置要下载的文件。无论如何,它都会崩溃。 - Adam Cherti
使用文件存储是可以的,但该API仅在Chrome上可用。 - Deni Spasovski

0

我刚刚重新打开了我2年前提交的Chrome bug,并为FF团队创建了另一个bug,这与在创建大型blob时浏览器崩溃有关。对于浏览器来说,生成大文件不应该是一个问题。


1
仍然崩溃!该死... - mik

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