The Future of Web Apps: A look at the File API

Remember the bad old days when uploading files to a website involved clicking the browse button on a file input, navigating to where the file is, clicking open and then doing it all over again for multiple files! Well, those days are numbered thanks to the File API.

What is it?

The File API is a powerful API that allows developers to handle files from a users file system and manipulate those files to be used within a web application all done locally without server processing.

What you can do with it?

There are many applications and scenarios where the File API can be very useful. The most obvious is to use it with the Drag and Drop API to access the files on the drop event allowing drag and drop uploading of files such as images. When the user drops the file(s) you can convert them to a data URL to give instant feedback and show thumbnails of the images being uploaded asynchronously, creating a seamless experience for the user.

A few examples in the wild:

For this article I put together an example showing off the File API, this demo works in both Firefox 3.6+ & Chrome 6 dev. Drag and drop any file from your desktop and see what happens…

* Disclosure: That’s my own web app.

How to use it

There are two ways you can access a file and manipulate with the File API. The first is through a file input and the files attribute.

document.getElementById("fileinput").files

The code above accesses the FileList object which contains an array like sequence of the files. Each file has several properties available to it such as name, size and type.

The other method of accessing a file is through the Drag and Drop API which also includes the FileList object on the dataTransfer object which is available on the drop event in the DnD API.

event.dataTransfer.files

Both methods return the same array like sequence. Dragging and dropping multiple files can be handled and if the file input has the multiple attribute it can also handle multiple files.

FileReader

In order to do something with the FileList object and manipulate the files to display back to the user without the need for a server we have the FileReader object. It does it’s processing asynchronously so as not to lock up the Browser UI as it is processing the file(s).

var reader = new FileReader();

reader.onload = function (evt) {
    // do something with the file once it's loaded
    var data = evt.target.result, // file is stored in the result attribute;
          img = document.createElement("img");

    img.src = data;
    document.getElementsByTagName("body").appendChild(img);
}
reader.readAsDataURL(file);

The above code we create a new FileReader object, we setup our onload function so we can manipulate the file once it has been loaded into memory and the last function tells the reader what we want to do with the file. In our case return it as a DataURL. There are two other methods available which are

readAsText()

and

readAsBinary()

.

Inside the onload event we’ll create a new image element, set its source to the result attribute and append it to the document body. This will display the image back to the user straight away.

Handling large files – File URL

In the previous examples I’ve shown you how to load in a file and manipulate it to show it back to the user. All these methods are essentially creating a copy of the file(s), using readAsDataURL/Binary/Text etc, and loading it into your available memory. This creates a problem when uses start to load many or very large files. Say a user tries to drag in a video that’s a couple hundred MB or they drag in a few videos! This will create an incredible amount of data that needs to be loaded into memory and will bring any machine to a grinding halt and most likely crash the browser. Thankfully the File API creators and contributors have thought of this and added a very useful attribute on the FileReader object called url.

URL you say?

The url is basically a randomly generated unique string that maps back to a physical file on your hard drive. The reason that this is useful is that this unique string can be used in placea where a generic url can be used in a html document (e.g. an image). Setting the image source to that of the unique string generated by the File API will allow you to display the image back to the user without having to load it into memory.

<img src="moz-filedata:8616e48b-2a2b-418d-9ad4-5669858cf038" />

The above example shows what the image source will look like using the url attribute in Firefox 4.

Consider this scenario. You have a image uploader on your photo website, a user drags in their photos, the dropped photos appear as a nice grid of scaled down versions but the user sees an issue and realises that one of the images needs retouching. They open the file in a photo editor, do the retouching, go back to the web app and click the upload button. The beauty of using the url is the changed file will still be uploaded without the user having to re-add it to the upload list as it’s a live link to the physical image on the file system.

Firefox 4, so far, is the only one to support the url attribute and even then it already has a bug where the unique string will only display the image if it’s loaded through a file input. Trying to display the image from a drop event won’t work. Though it should be fixed by the time Firefox 4 get’s a stable release.

Take a look at this demo in Firefox 4 which uses a file input to load files using the url attribute.

// Code showing url
var droppedFileURL = file.url;
...
img.src = droppedFileURL;

The code above is simple. Rather than attaching an event to load the image into memory and convert it to a data URL, we simply loop through the files and access the url attribute on the file object and set that to our image source. Less work for the developer, less strain on the user’s computer and an all round better approach.

Where it’s headed

Browser support as of the time of writing is limited to 2 browsers, Firefox 3.6 & Chrome 6, with varying degrees of support for the File API specification.

The File API is one of the first in a line of many API’s which are being worked on. Such as the FileWriter & Media Interface (web cam access) which will all work together to create some amazing potential. This is just the beginning of what is coming and is a step closer in making web apps first class citizens in the desktop world. The line is getting blurry.

Got something to say? Go for it!