Neil's Place

Scriptable IO

So one thing that is hard to do in Mozilla is read and write to files. This invoves a lot of creating of XPCOM components, initializing them and wrapping them in various other streams components. Or, you could use a library like jslib or similar. But it doesn’t have to be that way. What if an easier method was built-in:

// write a string to the file stuff.txt from the Home directory.
var file = IO.newFile("Home", "stuff.txt");
var stream = IO.newOutputStream(file, "text");
stream.writeString("This is a file\n");
stream.close();

And what if a similar technique could be used for reading and writing from files, sockets or other streams? What if this was reality?

See Scriptable IO for more details. Comments very welcome, especially on the API.

15 Responses to “Scriptable IO”

  1. Lucky Says:

    Microsoft has been doing this for years now, you may want to take a peak at their Object Model for a few pointers.

    It works extremely well, and is very simple to code upon.
    Just search for “Scripting.FileSystemObject”
    And/or I’ll be more then happy to assist.

    Your current syntax looks as awfully complex as using the xpcom instances already are!!

    Another model to look into is the “ADODB.Stream” it is far less work then doing the Input|Output Stream hoops you must jump through in xpcom.

  2. Boris Says:

    I haven’t read most of the API yet, but is the plan to expose this in all scripting contexts? Or only chrome ones? Or something else?

  3. George Says:

    Coming from the xbase world where everything was a simple function, I propose two functions:

    - IO.StringToFile(fileName,anyString,flags)

    and

    - anyText = IO.FileToString(fileName)

    Life was easier back then ;-)

  4. byron Says:

    ” For instance, using the location key ‘Desk’ will retrieve files in the desktop folder, and the location key ‘TmpD’ will retrieve files in the system’s temporary directory.”

    eww. can you please use non abbreviated names such as “Desktop” and “Temp”.

  5. mawrya Says:

    If this were reality I wouldn’t have to install jslib for a lot of projects. That would be nice indeed…not because jslib is bad, I couldn’t do without it, just because its one more thing that has to be managed. Does this overlap with the work the FUEL project is doing? Seems like there is a lot of thought going into making life easier for development in the javascript/chome realm, lately. Music to my ears.

    If indeed the success of Firefox is due, in large part, to the extension developer community that it has fostered, this type of work is worth its weight in gold.

    The extensions I build are used mostly internally at our company and always have some IO component to them. These types of features would be a great boon to a lot of developers like me who probably never show up on the public radar. With all the talk lately about the importance of the XULRunner platform, I can’t help but think a lot of the mileage could be had from just integrating the features jslib enshrouds into the Mozilla code base. Forge ahead my good man, forge ahead!

  6. Alex Vincent Says:

    API comments:

    nsIFile newFile, nsIFile newFileWithPath: shouldn’t these be nsILocalFile?

    nsISupports newInputStream(in nsIVariant base, in AString type);

    First, you really should not mix four different input types in the first argument. You’d be better off declaring a different method for each input type.

    Second, string types for the second argument? That’s like magic numbers - and evil for the exact same reason. I recommend using constants on the nsIScriptableIO interface, and requiring people pass in one of those named constants. Ditto for the modes of nsIOutputStream (though you could use single-bit flags for that).

    I may comment more later.

  7. Laurentj Says:

    I’m agree with George : IO.StringToFile and IO.FileToString are simplier. I love it.

    @Neil : your API is simplier than the actual API, it can be useful for a complex use, but it is still too complex for most of purpose (why a “normal” developer has to manage a “stream” ??).

  8. Mossop Says:

    Seems to me that this is something that could (should?) fit into FUEL so we have just one neat library for JS users. http://wiki.mozilla.org/FUEL

  9. Simon Says:

    I think you might also take a look how its done in PHP. I think it’s very simple and easy to use [http://www.php.net/manual/en/function.fopen.php]. I specially like the fgetscsv function, which lets you get a line from the file pointer and parse it for CSV fields.

  10. Enn Says:

    Lucky: I don’t understand. The example above would require 10-15 lines of code using the existing api instead of 4. Also, the “Scripting.FileSystemObject” object is very similar to what I’m proposing.

    Boris: chrome only, or privileged only, or something

    George: I can add a readAll function.

    Mossop: it is one and the same. See bug 380168

    Alex: they have classinfo so will be flattened for JS use. This API isn’t intended to be used from native code. “First, you really should not mix four different input types in the first argument.” No, this API is meant to be easier to use. Having multiple functions means you need to think about which one to use, rather than having a machine just do it for you. Also, strings are easier to type than constants.

  11. DigDug Says:

    Is this really necessary? You’re still creating the same classes, just hiding the Components calls.

    Most of the simple code I need for file IO is listed at MDC under code snippets. Creating a quick file object by cutting and pasting takes all of about 5 minutes. I can avoid using JSLib, and in the end I get a File() object which does exactly what I want. File.openWithFilePicker(). File.read(). File.readLines(). File.write(), File.save() etc. etc. etc.

    All the abstraction just seems silly. This isn’t that big of a problem. Its not like trying to dig through TB’s mail database or anything. Its well documented and easy to do.

  12. Enn Says:

    DigDug: yes, because if you have to resort to copying code from a sample, it almost always means that what you’re trying to do is too hard. Also, if you’re referring to http://developer.mozilla.org/en/docs/Code_snippets:File_I/O then no, that isn’t any near what I would call ‘well documented’. Documentation is about teaching developers how to use code and how and why it functions, so that they don’t blindly copy code from some sample without understanding why it isn’t the right code for what they are trying to do, which leads to buggy and poorly written code.

  13. ant Says:

    I’d prefer the idea posted by George above - there’s functions like it in PHP5, called “file_get_contents” and file_put_contents”, which do exactly what you’d expect. Much nicer than having to remember to do the whole open/do stuff/close dance each time.

  14. Lucky Says:

    Enn: I didn’t see much that resembled the MS IO, but I’ll look closer…

    The functions need to automagically handle whatever arguments is sent to it!!

    eg: if i say

    var f = new io.file(”my.txt”);

    then it should negotiate that value, even if it falls under chrome://..

    and or, i could just as easily:..

    var f = new io.file(”chrome://someext/global/you/get.the.idea”);

    also, directory recursion/ testing should be simple..

    var dirArray = io.folders(”some/path/”);

    var files = io.files(”some/path/”, /\.xml/);

    returning an array of the file objects
    [nsIFile, nsIFile, nsIFile, …]

    also, a built-in browse is nice..

    var f = io.browse(”Select a file”, io.BROWSEFILE);

    be more then happy to share some stuff i’ve done along these lines.

  15. Michael Says:

    This would be cool if they actually did it. I have my own collection of functions the I carry around to handle all my file.io stuff since I hate having to write it all the time. Just nice and simple fileGetContents(nsiFile) filePutContents(nsiFile,data) getUrlContents(aURL) and askForFile()

    It would be good if Firefox/Mozilla came with it by default.

Leave a Reply