I think it'd be great to have a *simple to use* API specifically for
loading local files on local pages (file://).
There's already DOM3 Load and Save, but few want anything to do with that
(it's not simple for one).
There's also the previous document.load, but it's half broken in Opera,
not implemented in Safari (unless things have changed recently) and isn't
very good with error handling in Firefox. In other words, it's a mess.
There's also XHR, but it doesn't really support file://. Firefox, Safari
and Opera have implemented file:// access, but they don't all use the same
security restrictions, don't all handle errors the same and don't simulate
HTTP status codes for local file operations. This makes loading a local
file a mess with XHR and makes it so you have to use different conditions
in the readystatechange callback compared to HTTP. It's possible though to
load a local file, but it's impossible to differentiate between the
different type of errors (like file not found, access denied, read error,
cross-origin attempt etc.). IE doesn't support accessing file:// with XHR,
so can't comment on it.
With that said, here's an idea (and what I'd like):
There should be a FileReader interface that supports just load(fileURI)
and error and load events (via onerror/onload or through addEventListener).
Then, there'd be different types of reader objects that inherit from
FileReader. The two that I'm suggesting are TextFileReader and
BinaryFileReader. (I believe it's better to separate functionality into 2
separate objects instead of mixing things.)
They would work like this:
var treader = new TextFileReader();
treader.addEventListener("load", function(e) {
alert(e.text);
}, false);
treader.addEventListener("error", function(e) {
alert(e.error.code);
}, false);
and
var breader = new BinaryFileReader();
breader.addEventListener("load", function(e) {
alert(e.bytes);
}, false);
breader.addEventListener("error", function(e) {
alert(e.error.code);
}, false);
'load' does not fire if there's an error. 'error' fires for the first
error (the code would return after the first error).
Nothing throws an exception. The author can do that in the error handler
if desired. That way, you can do things how you want. You can also easily
wrap things to use callback functions instead if you really wanted.
For the load event objects, there'd be a BinaryReaderLoadEvent that has a
bytes getter and a TextReaderLoadEvent that has a text getter. They would
inherit from Event. (I like these separate instead of having one event
object that has both .text and .bytes where one might be null or something)
For the error event object, there'd be a FileReaderErrorEvent object that
has an error getter that returns a FileReaderException object, which
inherits from DOMException and has a code getter that returns different
error codes for file not found etc. (that would have to be agreed upon).
It'd all look something like this (don't know idl stuff very well, but it
should be good enough to get the idea across)
interface FileReader {
onload
onerror
addEventListener
void load(uri);
};
interface TestFileReader : FileReader {
};
interface BinaryFileReader : FileReader {
};
interface TextFileReaderLoadEvent : Event {
readonly attribute string text;
};
interface BinaryFileReaderLoadEvent : Event {
readonly attribute array bytes;
};
interface FileReaderException : DOMException {
readyonly attribute unsigned short code;
};
// const unsigned short NOT_FOUND_ERR = 1;
// const unsigned short ACCESS_DENIED_ERR = 2;
// const unsigned short ORIGIN_VIOLATION_ERR = 3;
// const unsigned short READ_ERROR_ERR = 4;
interface FileReaderErrorEvent : Event {
readonly attribute FileReaderException error;
};
All the objects should be exposed on the window object so one can
extend/override them with prototypes and getters etc. if desired.
There'd by no sync version, only async like the examples above.
I don't think progress events and reading the file in chunks are needed
for this simple API.
I also specifically left out xml parsing, as that can be done with
DOMParser once you get the file text. (If DOMParser has shortcomings, it
should be improved.)
As for the encoding used for TextFileReader when reading the file, not
sure. I expect it to work just like document.load, XHR (with file://) and
DOM3 Load & Save work.
If you try to use a FileReader on a protocol besides file://, you'd get
the ORIGIN_VIOLATION_ERR in the error listener. (Note that
file://bark/dir/test.html <- and file://meow/dir/file.txt would be a
cross-origin violation for example.)
You'd also get the ORIGIN_VIOLATION_ERR in the error listener if you try
to use a FileReader on a non-file:// page.
Error handling is very important. -- Not for debugging, but for the
user-informative 'why things went wrong'. I absolutely hate it when a
generic exception is thrown and you can't tell if the file was not found
or if there's a cross-origin security error for example (like Firefox does
for XHR's open() when you specify a URI to a non-existent file). It makes
it difficult to give info on what went wrong.
That's the basic idea.
And, there could always be other readers like Base64FileReader and
DataURIFileReader later on. There could even be an XMLFileReader (if you
didn't want to create one yourself by wrapping the text reader and using
DOMParser).
I would also expect FileWriter objects, but saving that for later.
Now, with regards to the FileAPI, I see that it has objects and methods
for reading files. However, I don't currently see a way to get a files
object that has an entry that points to a file without using <input
type="file">.
If there was a way though to load a local file on a local web page
directly (without user-interaction and without <input type="file">) in JS
with the FileAPI, maybe none of this is needed.
Finally, I have to say that for the treader and breader examples above, I
really love the idea of things working just like that.
--
Michael