是否可以直接从Web工作者保存文件?

时间:2016-04-05 20:09:39

标签: file save web-worker

我有一个完全基于浏览器的(即没有后端)应用程序,它分析文件中的XML数据,每个文件平均大约250MB。实际的解析和分析发生在Web工作者中,它由FileReader实例以64KB块的形式提供数据,这一切都非常有效。

我有来自客户端的请求来扩展此应用程序,以便它可以生成包含原始输入文件和分析结果的.zip文件,并允许用户将该文件保存到本地计算机。使用这些内容在内存中生成.zip文件不是问题。问题在于将大量数据从生成它的Web工作者传回主浏览器线程,以便保存它;尝试这样做总会引发崩溃或内存不足异常。 (我尝试一次性传输字符串,一次传输一个块,我尝试使用ArrayBuffer作为可转移对象来避免复制。所有都以同样的方式失败。)

不幸的是,我不知道如何直接从工作线程调用文件保存操作。我知道从主浏览器线程这样做的几种方法,但是它们都需要能够创建DOM节点(工作线程当然不能做),或者使用接口(即msSaveBlob,saveAs)浏览器似乎暴露给工作线程。我花了一段时间在网上寻找可能性,但没有发现任何可用的东西; FileWriterSync看起来不错,但只有Chrome支持它,我也需要定位IE和Firefox。

我是否忽略了直接从网络工作者保存文件的方法?如果是这样,它是什么?或者我在这里运气不好?

1 个答案:

答案 0 :(得分:1)

tl;dr demo

您根本不需要将整个文件复制到客户端。实际上,您甚至不需要传输它。首先回顾一下。

这是从某些类型的数组创建Blob的方法:

// Some arbitrary binary data
const mydata = new Uint16Array([1,2,3,4,5]);
// mydata vs. mydata.buffer does not seem to make any difference
const blob = new Blob([mydata], {type: "octet/stream"});

您可以创建一个对象URL,它是由浏览器管理的原始Blob的副本,可以作为URL访问。我已经用巨大的文件完成了此操作,却没有看到性能影响:

const url = URL.createObjectURL(blob);

这通常是我下载URL的方式:

const link = document.createElement("a");
link.download = "data.bin";
link.href = e.data.link;
link.appendChild(new Text("Download data"));
link.addEventListener("click", function() {
    this.parentNode.removeChild(this);
    // remember to free the object url, but wait until the download is handled
    setTimeout(()=>{URL.revokeObjectURL(e.data.link);}, 500)
});
document.body.appendChild(link);

您可以通过在该链接上调用click事件来自动触发下载。我更愿意让用户决定何时下载。

所以,在一起:

worker.js

// Some arbitrary binary data
const mydata = new Uint16Array([1,2,3,4,5]);

self.onmessage = function(e) {
  console.log("Message: ",e.data)
  switch(e.data.name) {
    case "make-download" : 
        const blob = new Blob([mydata.buffer], {type: "octet/stream"});
        const url = URL.createObjectURL(blob);
        self.postMessage({name:"download-link", link:url});
    break;
    default:
      console.error("Unknown message:", e.data.name);
  }
}

main.js

var worker = new Worker("worker.js");
worker.addEventListener("message", function(e) {
  switch(e.data.name) {
    case "download-link" : {
       if(e.data.error) {
          console.error("Download error: ", e.data.error);
       }
       else {
          const link = document.createElement("a");
          link.download = "data.bin";
          link.href = e.data.link;
          link.appendChild(new Text("Download data"));
          link.addEventListener("click", function() {
              this.parentNode.removeChild(this);
              // remember to free the object url, but wait until the download is handled
              setTimeout(()=>{URL.revokeObjectURL(e.data.link);}, 500)
          });
          document.body.appendChild(link);
       }
       break;
    }
  default:
    console.error("Unknown message:", e.data.name);
  }
});

function requestDownload() {
  worker.postMessage({name:"make-download"});
}

在演示中单击“下载”时,可以在HEX编辑器中看到它:

enter image description here

看起来很好:)