Browser-Controlled File Storage

Part 3. Reading Saved Files

FileReader vs. DirectoryReader


First find your files, then read 'em!
Angry boss

Now that the image file is written to the local file storage, it can be accessed by a script belonging to the same origin. To display the saved image our code will use both FileSystem and FileReader APIs. Let's assume another button allows the user to fetch the image from the local storage and show it as part of HTML document:

<button onclick="showImage()">show image<button>

First request FileSystem access:

function showImage(){
 window.webkitRequestFileSystem(0,1024*1024,fsRequestSuccess, function(fileError){"Request failed. Code: "+fileError.code});
}

Then get the FileEntry based on its path:

function fsRequestSuccess(fileSystem){
 alert("File System request is satisfied.");
 var rootDirectory=fileSystem.root;
 rootDirectory.getFile(
  "/MyImages/image.png", // absolute path
  {create:false}, // Flags
  fileEntryCallback, // named success callback
  function(fileError){ // anonymous error callback
   alert("FileEntry cannot be obtained. Error code: "+fileError.code);
   }
 );
}

FileEntry success callback can be used to generate a new <img> element and append it to the body of our document. The image will have filesystem:http://example.com/temporary/MyImages/image.png URL as its source:

function fileEntryCallback(fileEntry){
 alert("FileEntry is obtained");
 var image=new Image();
 image.style.cssText="border:1px solid red;";
 image.src=fileEntry.toURL();
 document.body.appendChild(image);
}

Another way to display image data is to invoke a File instance from the obtained FileEntry and then to read the File through FileReader:

function fileEntryCallback(fileEntry){
 fileEntry.file(
  fileCallback, // named success callback
  function(fileError){ // anonymous error callback
   alert("File cannot be obtained.Code: "+fileError.code);
  }
 );
}
function fileCallback(file){
 var fileReader=new FileReader();
 fileReader.onload=function(event){
  var image=new Image();
  image.src=event.target.result;
  image.style.cssText="border:1px solid green;";
  document.body.appendChild(image);
 }
 fileReader.readAsDataURL(file);
}

This time the <img> element will have Base-64 encoded representation of the image as its source. Certainly, there are lots more ways of handling data retrieved from the local file storage. we have shown just the simplest scenarios. All in all, an application reading local data asynchronously may pass through the following stages:

requesting FileSystem access
+
specifying desired parameters
(size, type)
error callback
success callback

using getFile method
of DirectoryEntry
+
getting FileEntry
error callback
success callback

using file method
of FileEntry
+
getting File
error callback
success callback

using File and FileReader
to read the file data

It must be noted that writing multiple files to the local file storage or accessing a number of FileEntries from a directory should be performed in a WebWorker context: a Worker script will run in parallel to the main Web page. A Worker employs asynchronous APIs described above or synchronous interfaces without callbacks (FileSystemSync, EntrySync, DirectryEntrySync, FileEntrySync). If a directory contains several files, an application can use a special DirectoryReader interface to enumerate the files and get access to each of them. DirectoryReader is created by calling createReader method of a DirecctoryEntry:

var directoryReader=directoryEntry.createReader();
directoryReader.readEntries(successCallback, errorCallback);

Success callback accepts an array of entries as its argument. The array is used for iteration over file and directory entries and requesting their data. For synchronous scenarios DirectoryReaderSync is a counterpart of asynchronous DirectoryReader.

Conclusion

FileSystem and FileWriter APIs are really great solutions for developing feature-rich Web applications. Unfortunately, developers still cannot rely on universal support of the interfaces among all browser vendors. Ironically, Web developers are at a disadvantage over it compared with mobile developers: PhoneGap, a cross-platform mobile framework, supports FileSystem as the most convenient way to write data to native file systems. No doubt, the sooner major browser vendors implement file writing interfaces, the more innovative Web applications will be.