Device Storage API Redirect 1

Non-standard
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.

This API is available on Firefox OS for privileged or certified applications only.

Summary

The Device Storage API is used to access the file system within a Web app. Accessing the file system can be highly sensitive, and for that reason this API is available for privileged apps only.

Note: Accessing device storage is slow due to a limitation at the physical level. In many cases it can be faster to use an IndexedDB database to store files instead of physical device storage.

Accessing a storage

Entry point

It's possible to access a storage area by using the navigator.getDeviceStorage() method. It accept a string parameter which represent the name of the storage to get access to. The method returns a DeviceStorage object which is used to access the related storage area.

Firefox OS provide the following storage name:

  • apps: This storage area is used to store the user data needed by apps. As it is critical data, accessing this storage area require some extra privileges and is available for certified application only.
  • music: This is the storage area where music and sounds are stored.
  • pictures: This is the storage area where pictures are stored.
  • sdcard: This is the storage area that give access to the device's SDCard.
  • videos: This is the storage area where videos are stored.
var pics = navigator.getDeviceStorage('pictures');

To be able to use each of those storage areas, the application must declare them in its application manifest. For example, if the application want to access the sdcard storage area, it must have the "device-storage:sdcard" permission in its manifest.

"permissions": {
  "device-storage:videos":{ "access": "readonly" },
  "device-storage:pictures":{ "access": "readwrite" }
}

Using a storage

Once an application get access to a storage area, it's possible to add, get and remove files inside the area.

Add a file

Adding a file is done using the addNamed or add methods. The former allows to set an explicit name when storing a file while the latter creates a name automatically when the file is stored. Both methods are asynchronous and return a DOMRequest object to handle the success or error of the operation. This is very important as writing and reading files on a physical support is a slow process.

Those two methods expect a Blob as their first parameter. This object will be turned into a file under the hood and stored. When creating a Blob object, it's mandatory to give it a type. This type, which is a mime type, is important because some storage areas have restrictions based on the type:

  • music only accepts Blob with a valid audio mime type
  • pictures only accepts Blob with a valid image mime type
  • videos only accepts Blob with a valid video mime type
var sdcard = navigator.getDeviceStorage("sdcard");
var file   = new Blob(["This is a text file."], {type: "text/plain"});

var request = sdcard.addNamed(file, "my-file.txt");

request.onsuccess = function () {
  var name = this.result;
  console.log('File "' + name + '" successfully wrote on the sdcard storage area');
}

// An error typically occur if a file with the same name already exist
request.onerror = function () {
  console.warn('Unable to write the file: ' + this.error);
}

Note: Repository in a storage area are implicit. It's not possible to create explicitly an empty repository. If you want to use a repository structure you have to make it part of the name of the file to store. So if you want to store the file bar inside the foo repository, you have to use the addNamed method with the complete path name of the file addNamed(blob, "foo/bar"). This is also true when you want to retrieve a file using it's name (see below).

As file are added in a given restricted storage area for security reason, a file path name cannot start with "/" nor "../" (and "./" is pointless).

Get a file

Retrieving a file can be done in both ways: by using its name or by iterating the whole list of files.

The easiest way is to retrieve a file by its name using the get and getEditable methods. The former provides a File object (which act like a read only file) when the latter provides a FileHandle object (which allow to update the underlaying file). Both methods are asynchronous and return a DOMRequest object to handle the success or error of the operation.

var sdcard = navigator.getDeviceStorage('sdcard');

var request = sdcard.get("my-file.txt");

request.onsuccess = function () {
  var file = this.result;
  console.log("Get the file: " + file.name);
}

request.onerror = function () {
  console.warn("Unable to get the file: " + this.error);
}

The other way to retrieve files is by browsing the content of the storage area. This is possible using the enumerate and enumerateEditable methods. The former provides File objects when the latter provides FileHandle objects. Both methods are asynchronous and return a DOMCursor object to iterate along the list of files. A DOMCursor is nothing less than a DOMRequest with extra power to iterate asynchronously along a list of things (files in that case).

var pics = navigator.getDeviceStorage('pictures');

// Let's browse all the images available
var cursor = pics.enumerate();

cursor.onsuccess = function () {
  var file = this.result;
  console.log("File found: " + file.name);

  // Once we found a file we check if there is other results
  if (!this.done) {
    // Then we move to the next result, which call the cursor
    // success with the next file as result.
    this.continue();
  }
}

cursor.onerror = function () {
  console.warn("No file found: " + this.error);
}

It's possible to limit the number of result by passing two optional parameters to the enumerate and enumerateEditable methods.

The first parameter can be a string representing a sub folder to search inside.

The second parameter can be an object with a since property, which allow to limit the search to a given time period.

var pics = navigator.getDeviceStorage('pictures');

// Lets retrieve picture from the last week.
var param = {
  since: new Date((+new Date()) - 7*24*60*60*1000)
}

var cursor = pics.enumerate(param);

cursor.onsuccess = function () {
  var file = this.result;
  console.log("Picture taken on: " + file.lastModifiedDate);

  if (!this.done) {
    this.continue();
  }
}

Delete a file

A file can be removed from the storage area by simply using the delete method. This method just need the name of the file to delete. As all the other methods from the DeviceStorage interface, this one is also asynchronous and return a DOMRequest object to handle the success or error of the operation.

var sdcard = navigator.getDeviceStorage('sdcard');

var request = sdcard.delete("my-file.txt");

request.onsuccess = function () {
  console.log("File deleted");
}

request.onerror = function () {
  console.log("Unable to delete the file: " + this.error);
}

Storage information

Beyond accessing files, a storage area provide a few methods to easily reach some important information

Available space

One of the most important thing to know when storing files on a device is the amount of space available. The DeviceStorage interface provide two useful function dedicated to space:

  • freeSpace() to get the amount of free space available to store new files;
  • usedSpace() to get the amount of space used to store the files;

As those methods are asynchronous, they return a DOMRequest object to handle the success or error of the operation.

var videos = navigator.getDeviceStorage('videos');

var request = videos.usedSpace();

request.onsuccess = function () {
  // The result is express in bytes, lets turn it into megabytes
  var size = this.result / 1048576;
  console.log("The videos on your device use a total of " + size.toFixed(2) + "Mo of space.");
}

request.onerror = function () {
  console.warn("Unable to get the space used by videos: " + this.error);
}

Listening for change

As many applications can use a same storage area at the same time, it's sometime useful for an application to be aware of a change in that storage area. It's also useful for an application who want to perform asynchronous action without relaying on all the DOMRequest objects return by each method of the DeviceStorage interface.

To that end, a change event is triggered each time a file is created, modified or deleted. This event can be capture using the onchange property or the addEventListener() method. The event handler get a DeviceStorageChangeEvent object which is a regular Event object with two extra properties:

var sdcard = navigator.getDeviceStorage('sdcard');

sdcard.onchange = function (change) {
  var reason = change.reason;
  var path   = change.path;

  console.log('The file "' + path + '" has been ' + reason);
}

Specification

Not part of any specification.

Browser compatibility

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support ? ? Not supported Not supported Not supported
Feature Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support ? ? Not supported Not supported Not supported

See also

Document Tags and Contributors

 Contributors to this page: Sheppy
 Last updated by: Sheppy,