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

时间:2014-08-05 18:23:07

标签: javascript firefox firefox-addon

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

我浏览了the file I/O snippets on MDN,但这些片段对我没有多大帮助。

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

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.
});

1 个答案:

答案 0 :(得分:5)

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

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

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

选项1 - 使用OS.File

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

constructing a path之后(有一些常量帮助),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
  }
);

选项2 - 使用NetUtil

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

我们可以使用快捷方式,因为我们可以使用NetUtil.asyncFetch直接获取网址,这样就可以为我们提供一个可以传递给.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.
  });
});