How to read and write to files?

Talk about add-ons and extension development.
lightnb
Posts: 103
Joined: August 31st, 2005, 11:21 pm

How to read and write to files?

Post by lightnb »

From an extension, you can supposedly read and write data to regular system files, but I'm not sure of the right API to use to do that.

I found the nsIScriptableIO (https://developer.mozilla.org/en-US/doc ... riptableIO), which looks like it would do what I want, but it also has a note saying it was never actually implemented!

I also found File I/O (https://developer.mozilla.org/en-US/Add ... 2FFile_I_O) and nsIIOService (https://developer.mozilla.org/en-US/doc ... eURI%28%29).

There are also many other similarly named APIs too, so I'm confused by all of the options, and not sure what is the simplest way to read and write to text files from an add-on.

Specifically, I want to save a JSON string to a file and read it back later. Which is the right API to use?
lithopsian
Posts: 3664
Joined: September 15th, 2010, 9:03 am

Re: How to read and write to files?

Post by lithopsian »

nsIFile is the base interface for dealing with files, but it doesn't directly provide functions for reading and writing to them. For that you would typically use nsIFileInputStream and nsIFileOutputStream. You would probably start from nsILocalFile if you're dealing with a normal file on your local file system.

For files which are known as a URI, for example files inside jar or xpi archives, or remote files, you can use XMLHttpRequest to load the file. This contains a number of convenient methods for parsing file formats such as XML and JSON, so you will sometimes use it for reading local files.
lightnb
Posts: 103
Joined: August 31st, 2005, 11:21 pm

Re: How to read and write to files?

Post by lightnb »

I think I understand what to do now, but I'm not sure how to include nsIFileInputStream.

Code: Select all

GetFileContents = function(FileName){
      Components.utils.import("resource://gre/modules/FileUtils.jsm");
      var file = new FileUtils.File(FileName);
      return nsIFileInputStream.init(file,-1,-1);
}


Shouldn't there be a " Components.utils.import" line for nsIFileInputStream? How do I know what that is?
lithopsian
Posts: 3664
Joined: September 15th, 2010, 9:03 am

Re: How to read and write to files?

Post by lithopsian »

Examples:

Code: Select all

   readFile : function(file)
   {
      var response = "";
      try
      {
         if (file.exists() && file.isReadable())
         {
            var fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
            var sstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
            fstream.init(file, -1, 0, 0);
            sstream.init(fstream);
            var str = sstream.read(4096);
            while (str.length > 0)
            {
               response += str;
               str = sstream.read(4096);
            }
            sstream.close();
            fstream.close();
         }
      }
      catch(e) {};
      return response;
   },

   writeFile : function(file, data)
   {
      try
      {
         var stream = Cc["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Ci.nsISafeOutputStream);
         stream.QueryInterface(Ci.nsIFileOutputStream).init(file, 0x02 | 0x08 | 0x20, 0666, 0); // write, create, truncate, rw-rw-rw-
         stream.write(data, data.length);
         stream.finish();
      }
      catch(e) {};
   },


Scriptable input streams are used from javascript to access input streams because the read functions on nsIInputStream interface itself are not callable from javascript.

Safe output streams are a variation on file output streams that write to a copy of the file and then replace the original file in its entirety once the stream has been closed and file file safely written. This avoids file corruption in the event of something bad happeing halfway through the stream.
lightnb
Posts: 103
Joined: August 31st, 2005, 11:21 pm

Re: How to read and write to files?

Post by lightnb »

Thanks, I was able to use the code you posted and it's working now.
Noitidart
Posts: 1168
Joined: September 16th, 2007, 8:01 am

Re: How to read and write to files?

Post by Noitidart »

I think litho your example is synchronous right?



Here is what I use, its async. Here is copy paste example for scratchpad in "Browser" environment.

Code: Select all

/*start - example usage*/
var file = FileUtils.getFile("Desk", ["rawr.txt"]); //this gets file on desktop named 'rawr.txt'
//can also go: var file = FileUtils.File('C:\\Documents and Settings\\My User Name\\Desktop\\rawr.txt');

overwriteFile(file, 'blah blah blah', function (status) {
   alert('overwrite status == ' + Components.isSuccessCode(status));
});

readFile(file, function (dataReadFromFile, status) {
   alert('file read status == ' + Components.isSuccessCode(status));
   alert('contents of file is:\n' + dataReadFromFile);
});
/*end - example usage*/





Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource://gre/modules/NetUtil.jsm");
function overwriteFile(nsiFile, data, callback) {
   //data is data you want to write to file
   //if file doesnt exist it is created
   var ostream = FileUtils.openSafeFileOutputStream(file)
   var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
   converter.charset = "UTF-8";
   var istream = converter.convertToInputStream(data);
   // The last argument (the callback) is optional.
   NetUtil.asyncCopy(istream, ostream, function (status) {
      if (!Components.isSuccessCode(status)) {
         // Handle error!
         alert('error on write isSuccessCode = ' + status);
         return;
      }
      // Data has been written to the file.
      callback(status)
   });
}

function readFile(nsiFile, callback) {
   //you must pass a callback like function(dataReadFromFile, status) { }
   //then within the callback you can work with the contents of the file, it is held in dataReadFromFile
   //callback gets passed the data as string
   NetUtil.asyncFetch(file, function (inputStream, status) {
      //this function is callback that runs on completion of data reading
      if (!Components.isSuccessCode(status)) {
         alert('error on file read isSuccessCode = ' + status);
         return;
      }
      var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
      callback(data, status);
   });
}
lithopsian
Posts: 3664
Joined: September 15th, 2010, 9:03 am

Re: How to read and write to files?

Post by lithopsian »

Async is better. Most of the time I don't bother with NetUtils because XMLHttpRequest will do async reads with much more flexibility.
Noitidart
Posts: 1168
Joined: September 16th, 2007, 8:01 am

Re: How to read and write to files?

Post by Noitidart »

hey litho, im having an issue. im trying to help babylon with some stuff. so they have these content script files and image files they want to inject into a website. so i tried

Code: Select all

<img src="jar......">

but thats rejected due to security reasons.

so im trying to read the file and store the data in a string like 'data:image/png' or 'data:text/js' and then inject it into web page like this:

Code: Select all

<img src='data:image/png,...'>
<script src="data:text/js,....">

where ... is the read data



so the issue:
i'm trying to read a file from addon. its location is this:

Code: Select all

jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/babylon-spoonfeed@jetpack.xpi!/Praxis.js


if i paste this into the url bar it loads fine, but how to make a nsiFile out of this so i can read it?

im running into the problem here:

Code: Select all

FileUtils.File('jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/babylon-spoonfeed@jetpack.xpi!/Praxis.js');




my second question is. can you please help me on how to use FileRead api for this:
https://developer.mozilla.org/en-US/doc ... FileReader
lithopsian
Posts: 3664
Joined: September 15th, 2010, 9:03 am

Re: How to read and write to files?

Post by lithopsian »

Read jar files using XMLHttpRequest. They aren't real files, or at least the contents of them aren't, but XMLHttpRequest will accept the url that represents a file inside a jar and send you its contents. It will also automatically parse JSON, XML, and various other things.

I've never used the FileReader API. I think you can only read files that the user has selected manually (and certain other pseudo-files), for security reasons.
Noitidart
Posts: 1168
Joined: September 16th, 2007, 8:01 am

Re: How to read and write to files?

Post by Noitidart »

much thanks for super fast reply litho! ill look into xmlhttprequest :)
Noitidart
Posts: 1168
Joined: September 16th, 2007, 8:01 am

Re: How to read and write to files?

Post by Noitidart »

hey litho can you plz share some xmlhttprequest reader with me :( its 330am and im tired haha :P i wanted to just sleep right now and magically have code after work tomorrow haha. if ur busy or something i understand :)
max1million
Posts: 2810
Joined: November 15th, 2004, 5:03 am

Re: How to read and write to files?

Post by max1million »

convert the image to a data:image/png;base64, in plain text file in extension can read text to set var with

Code: Select all

var url = "https://developer.mozilla.org/en/DOM/XMLHttpRequest"; // chrome: file: etc also work
// var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].getService(Ci.nsIXMLHttpRequest);
var req = new XMLHttpRequest();
req.onload = function onload(e) {
  alert(req.responseText);
};
req.open("GET", url, true);  //(method, url, async)
req.send(null);
Noitidart
Posts: 1168
Joined: September 16th, 2007, 8:01 am

Re: How to read and write to files?

Post by Noitidart »

Much thanks max and litho! :)
Noitidart
Posts: 1168
Joined: September 16th, 2007, 8:01 am

Re: How to read and write to files?

Post by Noitidart »

oh my gosh i guys i just learned that i can still use my readFile function from above (quoted below).

i thought my funciton only took nsiFile however it uses NetUtil.asyncFetch:
https://developer.mozilla.org/en-US/doc ... etch%28%29

which accepts for aSource parameter:
The source to open asynchronously. This may be specified as an nsIURI, nsIFile, nsIChannel, nsIInputStream or as a string specifying the URL to open.


This is fantastic! I just learned a lot here.

so this is my code to base64 anything:

Code: Select all

Components.utils.import("resource://gre/modules/NetUtil.jsm");
readFile('file:///C:/Documents%20and%20Settings/SONY%20VAIO/My%20Documents/GitHub/babylon/subfolder/Button.png', function (dataReadFromFile, status) {
   if (!Components.isSuccessCode(status)) {
      Services.wm.getMostRecentWindow('navigator:browser').alert('error');
   } else {
      Services.wm.getMostRecentWindow('navigator:browser').alert('success ' + dataReadFromFile);
      Services.wm.getMostRecentWindow('navigator:browser').gBrowser.contentDocument.documentElement.innerHTML = '<img src="data:image;base64,' + Services.appShell.hiddenDOMWindow.btoa(dataReadFromFile) + '">';
   }
});


if i want to insert js file simply change

Code: Select all

Services.wm.getMostRecentWindow('navigator:browser').gBrowser.contentDocument.documentElement.innerHTML = '<script src="data:image;base64,' + Services.appShell.hiddenDOMWindow.btoa(dataReadFromFile) + '"></script>';


readFile from above

Code: Select all

function readFile(nsiFile, callback) {
   //you must pass a callback like function(dataReadFromFile, status) { }
   //then within the callback you can work with the contents of the file, it is held in dataReadFromFile
   //callback gets passed the data as string
   NetUtil.asyncFetch(nsiFile, function (inputStream, status) {
      //this function is callback that runs on completion of data reading
      if (!Components.isSuccessCode(status)) {
         //alert('error on file read isSuccessCode = ' + status);
         callback(null, status);
         return;
      }
      var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
      callback(data, status);
   });
}
TCaudillLG
Posts: 35
Joined: March 2nd, 2005, 4:27 pm
Location: Middletown, OH
Contact:

Re: How to read and write to files?

Post by TCaudillLG »

You think you've learned something from this thread, but trust me... when it comes time to actually implement this in your addon, you'll find you haven't learned very much. Biggest waste of time ever, the equivalent of trying to build a house on a swamp.
Post Reply