简体   繁体   English

如何在Firefox扩展中使用nsIArrayBufferInputStream异步将ArrayBuffer直接写入文件

[英]How to Asynchronously write an ArrayBuffer directly to file using nsIArrayBufferInputStream in Firefox extension

To make a long story short: How to Asynchronously write an ArrayBuffer directly to file using nsIArrayBufferInputStream in Firefox extension ? 简而言之:如何在Firefox扩展中使用nsIArrayBufferInputStream将ArrayBuffer直接异步写入文件? It seems that MDN does not have any documentation on nsIArrayBufferInputStream. 似乎MDN在nsIArrayBufferInputStream上没有任何文档。

I know I can use nsIStringInputStream and convert the BufferArray to String, but this poses a big performance hit also converting ArrayBuffer to string using this code: 我知道我可以使用nsIStringInputStream并将BufferArray转换为String,但这也对使用以下代码将ArrayBuffer转换为String造成了很大的影响:

String.fromCharCode.apply(null, new Uint16Array(buf));

Does not work if the buffer is 500 KB or bigger, so we must loop over it one char at a time: 如果缓冲区大于或等于500 KB则不起作用,因此我们必须一次循环一个字符:

for (let i = 0; i < buf.length; i++){
    s += String.fromCharCode(buf16[i]);
}

Or, I can use nsIBinaryOutputStream.writeByteArray but it cannot be used with NetUtil.asyncCopy (or can it?) 或者,我可以使用nsIBinaryOutputStream.writeByteArray,但不能与NetUtil.asyncCopy一起使用(或者可以吗?)

//this works ok, but is synchronous :-(
function writeBinFile(aFile, data){
    Components.utils.import("resource://gre/modules/FileUtils.jsm");
    let nsFile = Components.Constructor("@mozilla.org/file/local;1", Ci.nsILocalFile, "initWithPath");
    if(typeof aFile === 'string') aFile = nsFile(aFile);
    var stream = FileUtils.openSafeFileOutputStream(aFile, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
    var binaryStream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
    binaryStream.setOutputStream(stream);
    binaryStream.writeByteArray(data, data.length);
    FileUtils.closeSafeFileOutputStream(stream);
}

And the long story is... 总而言之...

I have been trying to use nsIArrayBufferInputStream http://dxr.mozilla.org/mozilla-central/source/netwerk/base/public/nsIArrayBufferInputStream.idl but with no success. 我一直在尝试使用nsIArrayBufferInputStream http://dxr.mozilla.org/mozilla-central/source/netwerk/base/public/nsIArrayBufferInputStream.idl,但没有成功。 the code I tried: 我试过的代码:

function fileWrite(file, data, callback) {
    Cu.import("resource://gre/modules/FileUtils.jsm");
    Cu.import("resource://gre/modules/NetUtil.jsm");
    let nsFile = Components.Constructor("@mozilla.org/file/local;1", Ci.nsILocalFile, "initWithPath");
    if (typeof file == 'string') file = new nsFile(file);
    let ostream = FileUtils.openSafeFileOutputStream(file)

    let istream = Cc["@mozilla.org/io/arraybuffer-input-stream;1"].createInstance(Ci.nsIArrayBufferInputStream);
    istream.setData(data, 0, data.length);

    let bstream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
    bstream.setInputStream(istream);

    //NetUtil.asyncCopy(istream, ostream,

    NetUtil.asyncCopy(bstream, ostream,
      function(status) {
          if (callback) callback(Components.isSuccessCode(status));
      }
    );
}

The ArrayBuffer data param is the responce from XMLHttpRequest: ArrayBuffer data参数是XMLHttpRequest的响应:

function getBinFile(url, dir) {
  let nsFile = Components.Constructor("@mozilla.org/file/local;1", Ci.nsILocalFile, "initWithPath");
  let oReq = new XMLHttpRequest();
  oReq.open("GET", url, true);
  oReq.responseType = "arraybuffer";
  oReq.onload = function(oEvent) {
    var arrayBuffer = oReq.response;
    if (arrayBuffer) {
        //let byteArray = new Uint8Array(arrayBuffer);
        let byteArray = arrayBuffer;
        dir = /\\$/.test(dir) ? dir: dir + '\\';
        let file = nsFile(dir + decodeURIComponent(url.split('/').pop()));
        fileWrite(file, byteArray);
    }
  };
  oReq.send(null);
}

calling like this: 像这样打电话:

  getBinFile( 'http://....', 'c:\\demo\\');

A file is created but with no contents! 文件已创建但没有内容!

I'm answering myself in case anyone stumbles upon this question... 我正在回答自己,以防有人偶然发现这个问题...

with help from Josh Matthews (of Mozilla) i found the answer: use byteLength instead of length 在Mozilla的Josh Matthews的帮助下,我找到了答案:使用byteLength而不是length

istream.setData(data, 0, data.byteLength);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM