是否可以直接从网络工作者保存文件? [英] Is it possible to save a file directly from a web worker?

查看:75
本文介绍了是否可以直接从网络工作者保存文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个完全基于浏览器的应用程序(即无后端),该应用程序分析文件中的XML数据,每个文件的平均大小约为250MB.实际的解析和分析是在Web Worker中进行的,它是由FileReader实例以64KB块的形式馈送数据的,其性能相当出色.

I have an entirely browser-based (i.e. no backend) application which analyzes XML data in files which average about 250MB each. The actual parsing and analysis happens in a web worker, which is fed data in 64KB chunks by a FileReader instance, and this is all quite performant.

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

I have a request from the client to expand this application so that it can generate a .zip file containing the original input file and the results of the analysis, and allow the user to save that file to her local machine. Generating a .zip file in memory with those contents isn't a problem. The problem lies in transferring that much data from the web worker which generates it back to the main browser thread, so that it can be saved; attempting to do this invariably provokes a crash or out-of-memory exception. (I've tried transferring strings all at once and a chunk at a time, and I've tried using an ArrayBuffer as a transferable object to avoid copying. All fail in the same fashion.)

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

Unfortunately, I don't know any way to invoke a file save operation directly from a worker thread. I know several methods of doing so from the main browser thread, but all of them require either the ability to create DOM nodes (which worker threads of course can't do), or the use of interfaces (i.e. msSaveBlob, saveAs) which no browser seems to expose to a worker thread. I've spent a while looking for possibilities on the web, but found nothing usable; FileWriterSync looked good, but only Chrome supports it, and I need to target IE and Firefox as well.

是否有一种我直接从Web Worker中保存文件的方法而被忽略了?如果是这样,那是什么?还是我只是运气不好?

Is there a method I've overlooked for saving files directly from a web worker? If so, what is it? Or am I just out of luck here?

推荐答案

tl; dr演示

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

tl;dr demo

You don't need to copy the entire file to the client side at all. You don't even need to transfer it, in fact. First a recap.

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

This is how to create Blob from some typed array:

// 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,该对象URL是浏览器管理的原始Blob的副本,可以作为URL访问.我已经用巨大的文件完成了此操作,却没有看到对性能的影响:

You can create an object URL, which is a copy of the original Blob managed by the browser and accessible as URL. I have done this with huge files without seeing performance impact:

const url = URL.createObjectURL(blob);

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

This is how I typically download URLs:

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事件来自动触发下载.我更愿意让用户决定何时下载.

You can trigger the download automatically by invoking click event on that link. I prefer to let the user decide when to download.

所以,在一起:

// 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编辑器中看到它:

When I click Download in my demo, I can see this in my HEX editor:

看起来很好:)

这篇关于是否可以直接从网络工作者保存文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆