将数据URI写入Firefox扩展中的文件

tin*_*ker 4 javascript firefox firefox-addon

我正在开发一个Firefox插件.我需要将一堆数据URI图像保存到磁盘.我该如何处理?

我浏览过MDN上的文件I/O片段,但这些片段对我没什么帮助.

有异步和同步方法.我想使用异步方法,但如何使用异步方法编写二进制文件

Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");

// file is nsIFile
var file = FileUtils.getFile("Desk", ["test.png"]);

// You can also optionally pass a flags parameter here. It defaults to
// FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE;
var ostream = FileUtils.openSafeFileOutputStream(file);

//base64 image that needs to be saved 
image ="iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";

// How can I create an inputstream from the image data URI?
var inputstream = createInputstream(image);

// The last argument (the callback) is optional.
NetUtil.asyncCopy(inputstream , ostream, function(status) {
  if (!Components.isSuccessCode(status)) {
    // Handle error!
    return;
  }

  // Data has been written to the file.
});
Run Code Online (Sandbox Code Playgroud)

nma*_*ier 5

听起来像你想不写数据的URI,但它"包含"二进制数据,所以我会回答这个问题.

首先,假设我们得到了一些实际的数据URI,(如果没有,添加data:application/octet-stream;base64,不是太难;)

// btoa("helloworld") as a placeholder ;)
var imageDataURI = "data:application/octet-stream;base64,aGVsbG93b3JsZA==";
Run Code Online (Sandbox Code Playgroud)

选项1 - 使用 OS.File

OS.File它的好处是真正的异步.另一方面,NetUtil只是主要是异步,因为stat主线程上会有调用,文件将被打开并且可能在主线程上关闭(这可能导致缓冲区刷新,从而阻塞主线程,而冲洗正在发生).

构造路径(有一些常量帮助)之后,OS.File.writeAtomic适合这项工作.

Components.utils.import("resource://gre/modules/osfile.jsm");

var file = OS.Path.join(OS.Constants.Path.desktopDir, "test.png");

var str = imageDataURI.replace(/^.*?;base64,/, "");
// Decode to a byte string
str = atob(str);
// Decode to an Uint8Array, because OS.File.writeAtomic expects an ArrayBuffer(View).
var data = new Uint8Array(str.length);
for (var i = 0, e = str.length; i < e; ++i) {
  data[i] = str.charCodeAt(i);
}

// To support Firefox 24 and earlier, you'll need to provide a tmpPath. See MDN.
// There is in my opinion no need to support these, as they are end-of-life and
// contain known security issues. Let's not encourage users. ;)
var promised = OS.File.writeAtomic(file, data);
promised.then(
  function() {
    // Success!
  },
  function(ex) {
    // Failed. Error information in ex
  }
);
Run Code Online (Sandbox Code Playgroud)

选项2 - 使用 NetUtil

NetUtil 如上所述,有一些缺点是不完全异步.

我们可以采用一种捷径,我们可以使用它NetUtil.asyncFetch来直接获取URL,这为我们提供了一个可以传递的流.asyncCopy.

Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");

// file is nsIFile
var file = FileUtils.getFile("Desk", ["test.png"]);

NetUtil.asyncFetch(imageDataURI, function(inputstream, status) {
  if (!inputstream || !Components.isSuccessCode(status)) {
    // Failed to read data URI.
    // Handle error!
    return;
  }

  // You can also optionally pass a flags parameter here. It defaults to
  // FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE;
  var ostream = FileUtils.openSafeFileOutputStream(file);

  // The last argument (the callback) is optional.
  NetUtil.asyncCopy(inputstream , ostream, function(status) {
    if (!Components.isSuccessCode(status)) {
      // Handle error!
      return;
    }

    // Data has been written to the file.
  });
});
Run Code Online (Sandbox Code Playgroud)