简体   繁体   English

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

[英]Write a data URI to a file in a Firefox extension

I am developing a Firefox addon. 我正在开发一个Firefox插件。 I need to save a bunch of data URI images to the disk. 我需要将一堆数据URI图像保存到磁盘。 How do I approach to this? 我该如何处理?

I have browsed through the file I/O snippets on MDN , but the snippets don't help me much. 我浏览过MDN上的文件I / O片段 ,但这些片段对我没什么帮助。

There are async and sync methods.I would like to use async method but how can I write a binary file using async method 有异步和同步方法。我想使用异步方法,但如何使用异步方法编写二进制文件

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

It sounds like you'd like to write not the data URI but the binary data it "contains", so I'll answer that. 听起来你不想写数据URI而是写“它包含”的二进制数据,所以我会回答这个问题。

First, lets assume we got some actual data URI, (if not, adding data:application/octet-stream;base64, isn't too hard ;) 首先,假设我们得到了一些实际的数据URI,(如果没有,添加data:application/octet-stream;base64,并不太难;)

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

Option 1 - Using OS.File 选项1 - 使用OS.File

OS.File has the benefit that it is truly async. OS.File具有真正异步的好处。 On the other hand, NetUtil is only mostly async, in that there will be stat calls on the main thread and the file will be opened and potentially closed on the main thread as well (which can lead to buffer flushes and hence block the main thread while the flush is happening). 另一方面, NetUtil 主要是异步的,因为主线程上会有stat调用,文件也会被打开并且可能在主线程上关闭(这可能导致缓冲区刷新,从而阻塞主线程)同时发生冲洗)。

After constructing a path (with some constants help), OS.File.writeAtomic is suited for the job. 构造路径 (带有一些常量帮助)之后, 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
  }
);

Option 2 - Using NetUtil 选项2 - 使用NetUtil

NetUtil has some drawbacks in that is is not fully async, as already stated above. NetUtil有一些缺点,即不完全异步。

We can take a shortcut in that we can use NetUtil.asyncFetch to directly fetch the URL, which gives us a stream we can pass along to .asyncCopy . 我们可以采用一种捷径,因为我们可以使用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.
  });
});

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

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