Kennenlernen der FileSystem APIs

HTML5 Rocks

Einführung

Ich habe immer gedacht, dass es praktisch wäre, wenn Dateien und Verzeichnisse von Webanwendungen gelesen und geschrieben werden könnten. Während der Trend momentan immer mehr vom Offline- zum Online-Betrieb geht, werden die Anwendungen immer komplexer. Hierbei hat sich das Fehlen von Dateisystem-APIs als Hindernis für die Weiterentwicklung des Webs erwiesen. Die Speicherung von binären Daten und die Interaktion mit diesen sollten nicht auf den Desktop beschränkt sein. Zum Glück sind sie dies dank des FileSystem APIs auch nicht mehr. Mit dem FileSystem API kann eine Web-App Daten erstellen, lesen, navigieren und in einen durch die Sandboxing-Technologie geschützten Abschnitt des lokalen Dateisystems des Nutzers schreiben.

Das API lässt sich in verschiedene Themen unterteilen:

  • Dateien lesen und bearbeiten: File/Blob, FileList, FileReader
  • Erstellen und schreiben: BlobBuilder, FileWriter
  • Verzeichnisse und Dateisystemzugriff: DirectoryReader, FileEntry/DirectoryEntry, LocalFileSystem

Browsersupport und Speicherbeschränkungen

Beim Verfassen dieses Artikels verfügt Google Chrome über die einzige funktionierende Implementierung des FileSystem APIs. Es gibt noch keine dedizierte Browser-Benutzeroberfläche für die Datei- und Kontingentverwaltung. Zur Speicherung von Daten auf dem System des Nutzers muss Ihre App unter Umständen ein Kontingent anfordern. Chrome kann zu Testzwecken jedoch mit der --unlimited-quota-for-files-Markierung ausgeführt werden. Wenn Sie eine App oder Erweiterung für den Chrome Web Store erstellen, können Sie statt einer Kontingentanforderung zudem die unlimitedStorage-Berechtigung der Manifest-Datei nutzen. Den Nutzern wird dann ein Berechtigungsdialogfeld angezeigt, in dem sie Speicher für eine App gewähren, ablehnen oder diesen erhöhen können.

Unter Umständen benötigen Sie die --allow-file-access-from-files-Markierung, wenn Sie Fehler in Ihrer App in file:// beseitigen. Ohne diese Markierungen tritt ein SECURITY_ERR- oder QUOTA_EXCEEDED_ERR-Dateifehler auf.

Dateisystem abfragen

Eine Web-App kann durch einen Aufruf von window.requestFileSystem() Zugriff auf ein durch die Sandboxing-Technologie geschütztes Dateisystem anfordern:

// Note: The file system has been prefixed as of Google Chrome 12:
window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;

window.requestFileSystem(type, size, successCallback, opt_errorCallback)
type
Gibt an, ob der der Dateispeicher persistent sein soll. Mögliche Werte sind window.TEMPORARY oder window.PERSISTENT. Daten, die unter Verwendung von TEMPORARY gespeichert werden, können vom Browser bei Bedarf entfernt werden, beispielsweise wenn mehr Speicherplatz benötigt wird. Als PERSISTENT ausgewiesener Speicher kann nicht gelöscht werden, sofern dies vom Nutzer oder von der App nicht explizit gestattet wird. Der Nutzer muss dann ein Kontingent für Ihre App einräumen. Siehe Anfordern von Speicherkontingent.
size
Die von der Anwendung benötigte Größe (in Byte) für den Speicher.
successCallback
Callback, das bei einer erfolgreichen Anforderung eines Dateisystems aufgerufen wird. Das Argument ist ein FileSystem-Objekt.
opt_errorCallback
Optionales Callback für die Behandlung von Fehlern oder bei der Ablehnung einer Anforderung zum Dateisystemabruf. Das Argument ist ein FileError-Objekt.

Wenn Sie requestFileSystem() zum ersten Mal aufrufen, wird neuer Speicher für Ihre App erstellt. Denken Sie unbedingt daran, dass dieses Dateisystem durch die Sandboxing-Technologie geschützt ist, das heißt, dass eine Web-App nicht auf die Dateien einer anderen App zugreifen kann. Außerdem bedeutet dies, dass Sie keine Dateien lesen bzw. in einen beliebigen Ordner auf der Festplatte des Nutzers – beispielsweise "Eigene Bilder", "Eigene Dokumente" und so weiter – schreiben können.

Nutzungsbeispiel:

function onInitFs(fs) {
  console.log('Opened file system: ' + fs.name);
}

window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);

Die "FileSystem"-Spezifikation definiert auch die Schnittstelle eines synchronen APIs, LocalFileSystemSync, die in Web Workers verwendet werden soll. In dieser Anleitung wird das synchrone API jedoch nicht behandelt.

Im restlichen Dokument verwenden wir denselben Handler für die Verarbeitung von Fehlern aus den asynchronen Aufrufen:

function errorHandler(e) {
  var msg = '';

  switch (e.code) {
    case FileError.QUOTA_EXCEEDED_ERR:
      msg = 'QUOTA_EXCEEDED_ERR';
      break;
    case FileError.NOT_FOUND_ERR:
      msg = 'NOT_FOUND_ERR';
      break;
    case FileError.SECURITY_ERR:
      msg = 'SECURITY_ERR';
      break;
    case FileError.INVALID_MODIFICATION_ERR:
      msg = 'INVALID_MODIFICATION_ERR';
      break;
    case FileError.INVALID_STATE_ERR:
      msg = 'INVALID_STATE_ERR';
      break;
    default:
      msg = 'Unknown Error';
      break;
  };

  console.log('Error: ' + msg);
}

Dieses Fehler-Callback ist zugegebenermaßen sehr allgemein, doch können Sie sich so zumindest eine Vorstellung machen. Sie möchten den Nutzern hingegen lesbare Meldungen bereitstellen.

Speicherkontingent anfordern

Zur Nutzung von als PERSISTENT gekennzeichnetem Speicher müssen Sie vom Nutzer die Berechtigung zur Speicherung persistenter Daten erhalten. Für als TEMPORARY gekennzeichneten Speicher gilt diese Einschränkung nicht, da der Browser temporär gespeicherte Daten bei Bedarf entfernen kann.

Um als PERSISTENT gekennzeichneten Speicher mit dem FileSystem API nutzen zu können, verfügt Chrome unter webkitStorageInfo über ein neues API zur Anforderung von Speicher:

window.webkitStorageInfo.requestQuota(PERSISTENT, 1024*1024, function(grantedBytes) {
  window.requestFileSystem(PERSISTENT, grantedBytes, onInitFs, errorHandler);
}, function(e) {
  console.log('Error', e);
});

Nachdem der Nutzer die Berechtigung eingeräumt hat, muss requestQuota() nicht mehr aufgerufen werden. Nachfolgende Aufrufe unterliegen einer NOOP-Anweisung (No Operation Performed), sodass kein Vorgang ausgeführt wird.

Darüber hinaus gibt es ein API zur Abfrage der aktuellen Kontingentnutzung und -zuweisung des Ursprungs: window.webkitStorageInfo.queryUsageAndQuota().

Mit Dateien arbeiten

Dateien in einer durch die Sandboxing-Technologie geschützten Umgebung werden durch die FileEntry-Schnittstelle dargestellt. "FileEntry" enthält die Arten von Eigenschaften (name, isFile, ...) und Methoden (remove, moveTo, copyTo, ...), die Sie von einem Standarddateisystem erwarten würden.

Eigenschaften und Methoden von FileEntry:

fileEntry.isFile === true
fileEntry.isDirectory === false
fileEntry.name
fileEntry.fullPath
...

fileEntry.getMetadata(successCallback, opt_errorCallback);
fileEntry.remove(successCallback, opt_errorCallback);
fileEntry.moveTo(dirEntry, opt_newName, opt_successCallback, opt_errorCallback);
fileEntry.copyTo(dirEntry, opt_newName, opt_successCallback, opt_errorCallback);
fileEntry.getParent(successCallback, opt_errorCallback);
fileEntry.toURL(opt_mimeType);

fileEntry.file(successCallback, opt_errorCallback);
fileEntry.createWriter(successCallback, opt_errorCallback);
...

Zum besseren Verständnis von FileEntry enthält der Rest dieses Abschnitts eine Reihe von Anleitungen zur Durchführung gängiger Aufgaben.

Datei erstellen

Sie können im Dateisystem mithilfe von getFile(), einer Methode der DirectoryEntry-Schnittstelle, eine Datei suchen oder erstellen. Nach der Anforderung dieser Datei wird ein FileSystem-Objekt an das Erfolgs-Callback weitergegeben. Dieses Objekt enthält eine DirectoryEntry (fs.root)-Klasse, die auf das Stammverzeichnis des Dateisystems der App verweist.

Mit dem folgenden Code wird im Stammverzeichnis des Dateisystems der App eine leere Protokolldatei "log.txt" erstellt:

function onInitFs(fs) {

  fs.root.getFile('log.txt', {create: true, exclusive: true}, function(fileEntry) {

    // fileEntry.isFile === true
    // fileEntry.name == 'log.txt'
    // fileEntry.fullPath == '/log.txt'

  }, errorHandler);

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

Nach der Anforderung an das Dateisystem wird der Erfolgs-Handler an ein FileSystem-Objekt weitergegeben. Innerhalb des Callbacks können wir fs.root.getFile() mit dem Namen der zu erstellenden Datei aufrufen. Sie können einen absoluten oder relativen Pfad weitergeben, der jedoch gültig sein muss. Der Versuch, eine Datei zu erstellen, deren unmittelbar übergeordnetes Element nicht existiert, ist beispielsweise ein Fehler. Das zweite Argument von getFile() ist ein Objektliteral, das das Verhalten der Funktion beschreibt, wenn die Datei nicht vorhanden ist. In diesem Beispiel wird die Datei durch create: true erstellt, falls sie nicht vorhanden ist, und ein Fehler ausgelöst, falls sie existiert (exclusive: true). Andernfalls – wenn create: false – wird die Datei einfach abgerufen und zurückgegeben. In jedem Fall werden die Dateiinhalte nicht überschrieben, weil wir nur einen Referenzeintrag auf die betreffende Datei abrufen.

Dateien nach Namen lesen

Mit dem folgenden Code wird die Datei "log.txt" abgerufen, ihr Inhalt mit dem FileReader-API gelesen und an den neuen Textbereich (<textarea>) auf der Seite angehängt. Falls die Datei "log.txt" nicht vorhanden ist, wird ein Fehler ausgelöst.

function onInitFs(fs) {

  fs.root.getFile('log.txt', {}, function(fileEntry) {

    // Get a File object representing the file,
    // then use FileReader to read its contents.
    fileEntry.file(function(file) {
       var reader = new FileReader();

       reader.onloadend = function(e) {
         var txtArea = document.createElement('textarea');
         txtArea.value = this.result;
         document.body.appendChild(txtArea);
       };

       reader.readAsText(file);
    }, errorHandler);

  }, errorHandler);

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

In eine Datei schreiben

Mit dem folgenden Code wird eine leere Datei "log.txt" erstellt, falls sie noch nicht existiert, und mit dem Text "Lorem ipsum" gefüllt.

function onInitFs(fs) {

  fs.root.getFile('log.txt', {create: true}, function(fileEntry) {

    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function(fileWriter) {

      fileWriter.onwriteend = function(e) {
        console.log('Write completed.');
      };

      fileWriter.onerror = function(e) {
        console.log('Write failed: ' + e.toString());
      };

      // Create a new Blob and write it to log.txt.
      var bb = new BlobBuilder(); // Note: window.WebKitBlobBuilder in Chrome 12.
      bb.append('Lorem Ipsum');
      fileWriter.write(bb.getBlob('text/plain'));

    }, errorHandler);

  }, errorHandler);

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

Dieses Mal rufen wir die createWriter()-Methode von "FileEntry" auf, um ein FileWriter-Objekt abzurufen. Im Erfolgs-Callback sind Ereignis-Handler für error- und writeend-Ereignisse eingerichtet. Die Textdaten werden geschrieben, indem ein BLOB (Binary Large Object) erstellt wird, an das Text angehängt und das dann an FileWriter.write() weitergegeben wird.

Daten an eine Datei anhängen

Mit dem folgenden Code wird der Text "Hello World" an das Ende unserer Protokolldatei angehängt. Es wird ein Fehler ausgelöst, falls die Datei nicht vorhanden ist.

function onInitFs(fs) {

  fs.root.getFile('log.txt', {create: false}, function(fileEntry) {

    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function(fileWriter) {

      fileWriter.seek(fileWriter.length); // Start write position at EOF.

      // Create a new Blob and write it to log.txt.
      var bb = new BlobBuilder(); // Note: window.WebKitBlobBuilder in Chrome 12.
      bb.append('Hello World');
      fileWriter.write(bb.getBlob('text/plain'));

    }, errorHandler);

  }, errorHandler);

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

Ausgewählte Dateien duplizieren

Mit dem folgenden Code kann ein Nutzer mithilfe von <input type="file" multiple /> mehrere Dateien auswählen und Kopien dieser Dateien im durch die Sandboxing-Technologie geschützten Dateisystem der App speichern.

<input type="file" id="myfile" multiple />
document.querySelector('#myfile').onchange = function(e) {
  var files = this.files;

  window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
    // Duplicate each file the user selected to the app's fs.
    for (var i = 0, file; file = files[i]; ++i) {

      // Capture current iteration's file in local scope for the getFile() callback.
      (function(f) {
        fs.root.getFile(file.name, {create: true, exclusive: true}, function(fileEntry) {
          fileEntry.createWriter(function(fileWriter) {
            fileWriter.write(f); // Note: write() can take a File or Blob object.
          }, errorHandler);
        }, errorHandler);
      })(file);

    }
  }, errorHandler);

};

Wir haben für den Dateiimport zwar eine Eingabe verwendet, doch lässt sich dasselbe Ziel auch problemlos mit HTML5 Drag & Drop erreichen.

Wie im Kommentar angemerkt ist, kann FileWriter.write() ein Blob- oder File-Objekt akzeptieren. Der Grund dafür ist, dass File von Blob erbt und Dateiobjekte daher BLOBs sind.

Datei entfernen

Mit dem folgenden Code wird die Datei "log.txt" gelöscht.

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getFile('log.txt', {create: false}, function(fileEntry) {

    fileEntry.remove(function() {
      console.log('File removed.');
    }, errorHandler);

  }, errorHandler);
}, errorHandler);

Mit Verzeichnissen arbeiten

Verzeichnisse in der Sandbox werden durch die DirectoryEntry-Schnittstelle dargestellt, die größtenteils dieselben Eigenschaften hat wie FileEntry, da sie von einer gemeinsamen Entry-Schnittstelle erben. DirectoryEntry verfügt jedoch über zusätzliche Methoden zur Bearbeitung von Verzeichnissen.

Eigenschaften und Methoden von DirectoryEntry:

dirEntry.isDirectory === true
// See the section on FileEntry for other inherited properties/methods.
...

var dirReader = dirEntry.createReader();
dirEntry.getFile(path, opt_flags, opt_successCallback, opt_errorCallback);
dirEntry.getDirectory(path, opt_flags, opt_successCallback, opt_errorCallback);
dirEntry.removeRecursively(successCallback, opt_errorCallback);
...

Verzeichnisse erstellen

Mit der getDirectory()-Methode von DirectoryEntry können Sie Verzeichnisse lesen oder erstellen. Sie können entweder einen Namen oder Pfad als zu suchendes bzw. zu erstellendes Verzeichnis weitergeben.

Mit dem folgenden Code wird im Stammverzeichnis beispielsweise ein Verzeichnis "MyPictures" erstellt:

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getDirectory('MyPictures', {create: true}, function(dirEntry) {
    ...
  }, errorHandler);
}, errorHandler);
  

Unterverzeichnisse

Ein Unterverzeichnis wird genauso erstellt wie jedes beliebige andere Verzeichnis. Das API löst jedoch einen Fehler aus, wenn Sie versuchen, ein Verzeichnis zu erstellen, dessen unmittelbar übergeordnetes Element nicht existiert. Hier besteht die Lösung darin, die einzelnen Verzeichnisse sequenziell zu erstellen, was bei einem asynchronen API recht schwierig ist.

Mit dem folgenden Code wird im Stammverzeichnis des "FileSystem"-Objekts der App eine neue Hierarchie, "music/genres/jazz", erstellt, indem jedes Unterverzeichnis nach der Erstellung des übergeordneten Ordners rekursiv hinzugefügt wird.

var path = 'music/genres/jazz/';

function createDir(rootDirEntry, folders) {
  // Throw out './' or '/' and move on to prevent something like '/foo/.//bar'.
  if (folders[0] == '.' || folders[0] == '') {
    folders = folders.slice(1);
  }
  rootDirEntry.getDirectory(folders[0], {create: true}, function(dirEntry) {
    // Recursively add the new subfolder (if we still have another to create).
    if (folders.length) {
      createDir(dirEntry, folders.slice(1));
    }
  }, errorHandler);
};

function onInitFs(fs) {
  createDir(fs.root, path.split('/')); // fs.root is a DirectoryEntry.
}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

Nachdem wir die Hierarchie "music/genres/jazz" erstellt haben, können wir den vollständigen Pfad an getDirectory() weitergeben und neue Unterordner oder Dateien darunter erstellen. Zum Beispiel:

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getFile('/music/genres/jazz/song.mp3', {create: true}, function(fileEntry) {
    ...
  }, errorHandler);
}, errorHandler);

Inhalt eines Verzeichnisses lesen

Um den Inhalt eines Verzeichnisses zu lesen, erstellen Sie ein DirectoryReader-Objekt und rufen Sie seine readEntries()-Methode auf. Es gibt keine Garantie, dass alle Einträge eines Verzeichnisses in einem einzigen Aufruf an readEntries() zurückgegeben werden. Daher ist es erforderlich, DirectoryReader.readEntries() so oft aufzurufen, bis keine Ergebnisse mehr zurückgegeben werden. Der folgende Code veranschaulicht dies:

<ul id="filelist"></ul>
function toArray(list) {
  return Array.prototype.slice.call(list || [], 0);
}

function listResults(entries) {
  // Document fragments can improve performance since they're only appended
  // to the DOM once. Only one browser reflow occurs.
  var fragment = document.createDocumentFragment();

  entries.forEach(function(entry, i) {
    var img = entry.isDirectory ? '<img src="folder-icon.gif">' :
                                  '<img src="file-icon.gif">';
    var li = document.createElement('li');
    li.innerHTML = [img, '<span>', entry.name, '</span>'].join('');
    fragment.appendChild(li);
  });

  document.querySelector('#filelist').appendChild(fragment);
}

function onInitFs(fs) {

  var dirReader = fs.root.createReader();
  var entries = [];

  // Call the reader.readEntries() until no more results are returned.
  var readEntries = function() {
     dirReader.readEntries (function(results) {
      if (!results.length) {
        listResults(entries.sort());
      } else {
        entries = entries.concat(toArray(results));
        readEntries();
      }
    }, errorHandler);
  };

  readEntries(); // Start reading dirs.

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

Verzeichnis entfernen

Das Verhalten der DirectoryEntry.remove()-Methode ist mit der von FileEntry identisch. Der Unterschied: Wenn Sie versuchen, ein nicht leeres Verzeichnis zu löschen, führt dies zu einem Fehler.

Mit dem folgenden Code wird das leere Verzeichnis "jazz" aus "/music/genres/" entfernt:

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getDirectory('music/genres/jazz', {}, function(dirEntry) {

    dirEntry.remove(function() {
      console.log('Directory removed.');
    }, errorHandler);

  }, errorHandler);
}, errorHandler);

Verzeichnis rekursiv entfernen

Wenn Sie ein unerwünschtes Verzeichnis haben, das Einträge enthält, leistet removeRecursively() Abhilfe. Damit werden das Verzeichnis und sein Inhalt rekursiv gelöscht.

Mit dem folgenden Code werden das Verzeichnis "music" und alle darin enthaltenen Dateien und Verzeichnisse rekursiv entfernt:

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getDirectory('/misc/../music', {}, function(dirEntry) {

    dirEntry.removeRecursively(function() {
      console.log('Directory removed.');
    }, errorHandler);

  }, errorHandler);
}, errorHandler);

Kopieren, umbenennen und verschieben

FileEntry und DirectoryEntry weisen gemeinsame Vorgänge auf.

Eintrag kopieren

Sowohl FileEntry als auch DirectoryEntry verfügen über eine copyTo()-Methode zum Duplizieren vorhandener Einträge. Bei dieser Methode werden für Ordner automatisch rekursive Kopiervorgänge ausgeführt.

Mit dem folgenden Code wird die Datei "me.png" von einem Verzeichnis in ein anderes kopiert:

function copy(cwd, src, dest) {
  cwd.getFile(src, {}, function(fileEntry) {

    cwd.getDirectory(dest, {}, function(dirEntry) {
      fileEntry.copyTo(dirEntry);
    }, errorHandler);

  }, errorHandler);
}

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  copy(fs.root, '/folder1/me.png', 'folder2/mypics/');
}, errorHandler);

Eintrag verschieben oder umbenennen

Mit der moveTo()-Methode von FileEntry und DirectoryEntry können Sie eine Datei oder ein Verzeichnis verschieben oder umbenennen. Das erste Argument ist das übergeordnete Verzeichnis, in das die Datei verschoben werden soll, das zweite ist ein optionaler neuer Name für die Datei. Wird kein neuer Name angegeben, so wird der ursprüngliche Name der Datei verwendet.

Im folgenden Beispiel wird "me.png" in "you.png" umbenannt, allerdings wird die Datei nicht verschoben:

function rename(cwd, src, newName) {
  cwd.getFile(src, {}, function(fileEntry) {
    fileEntry.moveTo(cwd, newName);
  }, errorHandler);
}

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  rename(fs.root, 'me.png', 'you.png');
}, errorHandler);

Im folgenden Beispiel wird die im Stammverzeichnis befindliche Datei "me.png" in den Ordner "newfolder" verschoben.

function move(src, dirName) {
  fs.root.getFile(src, {}, function(fileEntry) {

    fs.root.getDirectory(dirName, {}, function(dirEntry) {
      fileEntry.moveTo(dirEntry);
    }, errorHandler);

  }, errorHandler);
}

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  move('/me.png', 'newfolder/');
}, errorHandler);

FileSystem: URLs

Das FileSystem API weist ein neues URL-Schema, filesystem:, auf, mit dem src- oder href-Attribute gefüllt werden können. Wenn Sie beispielsweise ein Bild anzeigen und sein fileEntry-Objekt abrufen wollten, würde durch einen Aufruf von toURL() die filesystem:-URL der Datei zurückgegeben:

var img = document.createElement('img');
img.src = fileEntry.toURL(); // filesystem:http://example.com/temporary/myfile.png
document.body.appendChild(img);

Liegt Ihnen bereits eine filesystem:-URL vor, können Sie alternativ mit resolveLocalFileSystemURL() das fileEntry-Objekt zurückgeben:

window.resolveLocalFileSystemURL = window.resolveLocalFileSystemURL ||
                                   window.webkitResolveLocalFileSystemURL;

var url = 'filesystem:http://example.com/temporary/myfile.png';
window.resolveLocalFileSystemURL(url, function(fileEntry) {
  ...
});

Abschluss

Einfaches Beispiel

In dieser Demo werden die Dateien/Ordner im Dateisystem aufgelistet.

HTML5-Terminal

Diese Shell repliziert einige der allgemeinen Vorgänge in ein UNIX-Dateisystem (wie cd, mkdir, rm, open und cat) und abstrahiert dazu das FileSystem API. Zum Hinzufügen von Dateien ziehen Sie sie von Ihrem Desktop und legen Sie sie im Terminal unten ab.

Anwendungsfälle

In HTML5 sind verschiedene Speicheroptionen verfügbar, doch "FileSystem" unterscheidet sich insofern, als es darauf angelegt ist, clientseitigen Anwendungsfällen für Speicher gerecht zu werden, die durch Datenbanken nicht optimal abgedeckt werden. Im Allgemeinen sind dies Anwendungen zur Handhabung großer binärer BLOBs und/oder zur Freigabe von Daten für Anwendungen außerhalb des Browserkontexts.

In der Spezifikation sind verschiedene Anwendungsfälle aufgeführt:

  1. Persistenter Uploader
    • Werden Dateien oder Verzeichnisse zum Upload ausgewählt, so kopiert er die Dateien in eine lokale Sandbox und lädt sie jeweils blockweise hoch.
    • Uploads können nach Browserabstürzen, unterbrochenen Netzwerkverbindungen und so weiter neu gestartet werden.
  2. Videospiel-, Musik- oder andere App mit vielen Medien-Assets
    • Ein oder mehrere Tarballs werden heruntergeladen und lokal in einer Verzeichnisstruktur erweitert.
    • Der Download funktioniert bei jedem beliebigem Betriebssystem.
    • Die App kann die als Nächstes benötigten Assets im Hintergrund vorab abrufen, sodass zum Fortfahren mit dem nächsten Level eines Spiels oder zur Aktivierung einer neuen Funktion keine Wartezeiten für Downloads entstehen.
    • Sie nutzt diese Assets durch direkte Dateilesevorgänge oder die Übergabe lokaler URIs an Bild- oder Video-Tags, WebGL-Asset Loader und so weiter direkt im lokalen Cache.
    • Die Dateien können ein beliebiges binäres Format aufweisen.
    • Auf Serverseite ist ein komprimierter Tarball häufig wesentlich kleiner als eine Sammlung von einzeln komprimierten Dateien. Zudem schließt ein Tarball anstelle von 1000 kleinen Dateien weniger Suchvorgänge ein, während alle anderen Gegebenheiten identisch sind.
  3. Audio-/Fotoeditor mit Offlinezugriff oder lokalem Cache zur Beschleunigung
    • Die Daten-BLOBs sind potenziell recht groß und bieten Lese-/Schreibzugriff.
    • Möglicherweise sollen eingeschränkte Schreibzugriffe auf Dateien stattfinden und dabei beispielsweise nur die ID3/EXIF-Tags überschrieben werden.
    • Es wäre nützlich, Projektdateien durch Erstellen von Verzeichnissen organisieren zu können.
    • Bearbeitete Dateien sollten für clientseitige Anwendungen wie iTunes oder Picasa zugreifbar sein.
  4. Offline-Videobetrachter
    • Lädt umfangreiche Dateien (> 1 GB) zur späteren Anzeige herunter
    • Erfordert effiziente Such- und Streaming-Funktionen
    • Muss eine URI an das Video-Tag übergeben können
    • Sollte auf teilweise heruntergeladene Dateien zugreifen können, damit Sie sich beispielweise die erste Episode der DVD ansehen können, auch wenn Ihr Download beim Besteigen des Flugzeugs noch nicht abgeschlossen war
    • Sollte in der Lage sein, eine einzelne Episode aus der Mitte eines Downloads abzurufen und nur diese an das Video-Tag zu übergeben
  5. Offline-Webmail-Client
    • Lädt Anhänge herunter und speichert sie lokal
    • Speichert vom Nutzer ausgewählte Anhänge zum späteren Hochladen im Cache
    • Muss auf zwischengespeicherte Anhänge und Miniaturansichten zur Anzeige und zum Upload verweisen können
    • Sollte den UA-Download-Manager wie bei der Kommunikation mit einem Server auslösen können
    • Sollte eine E-Mail mit Anhängen als mehrteiligen Post hochladen können, statt jeweils eine Datei in einer XHR-Anfrage zu senden

Referenzspezifikationen

Comments

0