WebAPI/FileHandleAPI

From MozillaWiki
Jump to: navigation, search

Goals

Provide the ability to write to a file, as well the locking mechanisms needed to allow writing safely. FileHandle is also known as low-level file-CRUD support.

Status

Basic functionality and support in IndexedDB is done, support in DeviceStorage remaining.

For details about the development, refer to

API

partial interface IDBDatabase
{
  IDBRequest mozCreateFileHandle(DOMString name, optional DOMString type);
};
interface IDBFileHandle
{
  readonly attribute IDBDatabase database;
};
interface FileHandle
{
  LockedFile open(optional /* "readonly" */ DOMString mode);

  DOMRequest getFile();

  [TreatNonCallableAsNull] attribute Function? onabort;

  [TreatNonCallableAsNull] attribute Function? onerror;
};
interface LockedFile
{
  readonly attribute FileHandle fileHandle;

  readonly attribute DOMString mode;

  readonly attribute boolean active;

  attribute any? location;

  FileRequest getMetadata(optional FileMetadataParameters parameters);

  FileRequest readAsArrayBuffer(unsigned long long size);

  FileRequest readAsText(unsigned long long size, optional DOMString encoding);

  FileRequest write(DOMString or ArrayBuffer or Blob value);

  FileRequest append(DOMString or ArrayBuffer or Blob value);

  FileRequest truncate(optional unsigned long long size);

  FileRequest flush();

  void abort();

  [TreatNonCallableAsNull] attribute Function? oncomplete;

  [TreatNonCallableAsNull] attribute Function? onabort;

  [TreatNonCallableAsNull] attribute Function? onerror;
};
interface FileRequest : DOMRequest
{
  readonly attribute LockedFile lockedFile;

  [TreatNonCallableAsNull] attribute Function? onprogress;
};
dictionary FileMetadataParameters {
  boolean size = true;

  boolean lastModified = true;
};

Example

Here are few examples about how to use FileHandle API.

Create a file

var request = myDatabase.mozCreateFileHandle("test.bin", "binary");
request.onsuccess = function(event) {
  var myFile = event.target.result;
}

// The file is now only referenced from JS, it will be automatically deleted after a
// GC, if we don't store it in an objectstore (useful for creating temporary files).

Store the file in an objectstore

var transaction = myDatabase.transaction(["test"], "readwrite");
var objectStore = transaction.objectStore("test");
var request = objectStore.add(myFile, myKey);
request.onsuccess = function(event) {
  // The file is now referenced from database too.
}

// If we store the same file using a different key or even in a different objectstore,
// it won't be stored as a separate file, the operation will only add another database
// reference.

A simple write operation

var lockedFile = myFile.open("readwrite");
var request = lockedFile.write("foo");
request.onsuccess = function(event) {
  // The string "foo" has been written.
}

A simple read operation

var lockedFile = myFile.open();
var request = lockedFile.readAsText(3);
request.onsuccess = function(event) {
  var text = event.target.result;
  // 3 characters have been read.
}

Write a 32 bit unsigned integer

var buffer = new ArrayBuffer(4);
var view = new Uint32Array(buffer);
view[0] = 1;

var lockedFile = myFile.open("readwrite");
var request = lockedFile.write(buffer);
request.onsuccess = function(event) {
  // The integer has been written.
}

Atomic increment of a counter somewhere in the file

var lockedFile = myFile.open("readwrite");
lockedFile.location = 123;
lockedFile.readAsArrayBuffer(4).onsuccess = function(event) {
  var buffer = event.target.result;
  var view = new Uint32Array(buffer);
  view[0] = view[0] + 1;
  lockedFile.location = 123;
  lockedFile.write(buffer);
}

Update the progress bar during a read or write

request.onprogress = function(event) {
  var progress = document.getElementById("progress");
  progress.value = event.loaded;
  progress.max = event.total;
}

Store a snapshot of the file

myFile.getFile().onsuccess = function(event) {
  var file = event.target.result;
  var transcation = myDatabase.transaction(["snapshots"], "readwrite");
  var objectStore = transaction.objectStore("snapshots");
  objectStore.add(file, snapshotKey).onsuccess = function(event) {
    // A new readonly copy of the file has been created.
  }
}

// myFile.getFile() can be also used to pass file objects to a FileReader, XHR, etc.

ToDo

  • Multi-process support in IndexedDB (a requirement for use in B2G)
  • Synchronous API (for use in workers)
  • Fast methods or explicit close() method to avoid multiple round-trips to the main thread (to improve performance of multiple small reads/writes requested in a row)

Articles

Articles mentioning / discussing the FileHandle API:

Links