Problem with open and save text files

Hello,
I am using Firefox 41.0.1 and jpm

This is my first Add-on and i am trying to save all my open Tabs in a textfile and vice versa open a textfile and open all Urls into a new tab.
I can get the url from a tab and open a tab, but i have problems to handle text, files and stream.

I read the Tutorials about files and text-streams
developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/io_file
developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/io_text-streams

Does anybody have a tip on how to do this?
Do I have to use inputStream and how?
Is the SDK the best way?

What do you want to save? Just the addresses? The pages themselves? In what format? HTML? JSON?

Once you have some text, and a file object, you can write it easily enough:

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();

Tssssss nsiFile!!!

Why not OS.File? :stuck_out_tongue:

  var promise_write = OS.File.writeAtomic(OS.Path.join(OS.Path.Constants.desktopDir, 'my file.txt'), 'blah blah blah', {encoding:'utf-8'}); 

Boom done.

If you want validation on the promise then you do this after it:

promise_write.then(
    function(aVal) {
        console.log('Fullfilled - promise_write - ', aVal);
    },
    function(aReason) {
        var rejObj = {name:'promise_write', aReason:aReason};
        console.error('Rejected - promise_write - ', rejObj);
    }
).catch(
    function(aCaught) {
        var rejObj = {name:'promise_write', aCaught:aCaught};
        console.error('Caught - promise_write - ', rejObj);
    }
);

One day I’ll move into the 21st century :wink:

Async is better than sync from IO, but I don’t like the promise API. Maybe when it stops crashing stuff, then I’ll start using it. Perhaps I’d convince myself to use OS.File if I needed file I/O in a new addon, but that looks very unlikely so one less decision for me …

What do you want to save? Just the addresses? The pages themselves? In what format? HTML? JSON?

I want to save just the adress (url) in a text file.
I tried writeTextToFile from the Low-Level APIs

function writeTextToFile(text, filename) {
  var fileIO = require("sdk/io/file");
  var TextWriter = fileIO.open(filename, "w");
  if (!TextWriter.closed) {
    TextWriter.write(text);
    TextWriter.close();
  }
}

And start it like this

writeTextToFile("Hello", "TestWrite.txt");

But I get a mistake

Message: [Exception... "Component returned failure code: 0x80520001 (NS_ERROR_FILE_UNRECOGNIZED_PATH) [nsILocalFile.initWithPath]"

Tomorrow i will read a bit more on how to handle the (file)path and try your example.

With the SDK API you are using, you need to supply an absolute pathname in native format, for example /var/tmp/file.txt. For compatibility, it is recommended to create paths using the join() function, but absolute native paths are never going to be very cross-platform compatible anyway. Unfortunately the API doesn’t have a built-in way to get a relative path, for example to a file in the profile directory. For this you have to get require chrome and use the dirsvc API:

Tada!

Neat! There’s a module for almost everything :wink:

Thanks for all the help. It took a while, but i made some progress.
@noitidart OS.File was a good reference.
But I think it must be OS.Constants.Path.desktopDir instead of OS.Path.Constants.desktopDir

@Lithopsian You’re right absolute pathname are not really very cross-platform compatible

@MartijnJ posted anothert way to get the path to special directories.
What is the difference between

require('sdk/system').pathFor('Desk');

and

OS.Constants.Path.desktopDir

Is one better or more future-proof?

OS.Constants is not an SDK module. It is a service, so you would need to require chrome and then get the service. It provides singleton path objects for locations such as the desktop and profile directories, which is efficient and fast.

sdk/system is an SDK module. pathFor returns a new path object for the key you provide. io/file is an SDK module that wraps the code snippet that I provided. Slightly less efficient, but if you don’t need to require chrome for anything else, then this is simpler. If you want to do a lot of file IO then go with OS.File, which is off-main-thread, and use OS.Constants. Mozilla haven’t yet announced they are giving up on the high level SDK APIs, but WebExtensions is the anointed golden boy of the future.

Just to keep me on track. There are different ways to make extensions :

  • Overlay extensions [life span 1-2 years]
    Characteristic: XUL / XPCOM
  • Bootstrapped extensions [life span ???]
    Characteristic: No APIs but JavaScript Modules (require chrome, OS.File)
  • SDK extensions
    Characteristic: Set of high-level APIs [likely to work in the future] and low-level APIs [likely NOT to work in the future]
  • WebExtension [The future, but still in development]
    Characteristic: Set of APIs

I am not sure if the summary is correct and I hope its not completely wrong.
Is there some information, on how long the Bootstrapped and SDK extensions will be supported?

And just one more question. If I dont want to work with a static file, but let the user select (like the open and safe dialog box). Is it possible to “get” these dialog boxes?

[quote=“christoph_b, post:11, topic:4711”]
I am not sure if the summary is correct and I hope its not completely wrong.Is there some information, on how long the Bootstrapped and SDK extensions will be supported?[/quote]
The different extension types will probably continue to be supported at least for a year (more than that, most likely).

See nsIFilePicker.

That is what I was looking for.

Here is a good tutorial which use nsIFilePicker and show how to use it with require(“chrome”)
Tutorial