smart | Webentwicklung
Alles rund um HTML5, PHP, WordPress & Co.

HTML5 WebStorage API: Dateien mithilfe der FileAPI speichern

10. Mai 2013
Stephan
HTML5 Offline-Technologien

Im letzten Artikel hatte ich euch bereits eine kurze Einführung in die HTML5 WebStorage API gegeben. Dabei wurde deutlich, dass als Datentyp für einen zu speichernden Wert nur DOMString unterstützt wird.

Trotzdem ist es möglich auch andere Datentypen, wie z.B. Arrays, Objekte oder aber sogar Dateien mittels der WebStorage API zu speichern. Dazu müssen wir einfach die Datentypen vor dem Speichern in einen String umwandeln.

Wie ihr mithilfe der File API Dateien in einen String umwandelt und via WebStorage API speichert, zeige ich euch nun in diesem Artikel.

HTML-Grundgerüst

Für unser Beispiel benötigen wir nur ein input-Feld zur Angabe einer Datei. Außerdem wollen wir die gespeicherte Datei später auch wieder auslesen und den Dateiinhalt anzeigen. Aus diesem Grund fügen wir noch eine Schaltfläche und ein iFrame zum Anzeigen des Dateiinhalts ein:

<input id="chooseFile" type="file" name="chooseFile" />
<input id="showFile" type="button" value="Datei anzeigen" />
<iframe width="500" height="500" />

Dateien mittels File & WebStorage API speichern

Damit wir eine Datei im WebStorage des Browsers speichern können, müssen wir die Datei bzw. den Dateiinhalt in einen String umwandeln. Dazu nutzen wir die File API und im konkreten Fall die FileReader-Klasse. Mithilfe dieser Klasse lesen wir den Inhalt der Datei als Data-URL, also als base64-kodierten String ein:

$(document).ready(function()
{
    $('#chooseFile').bind('change', function()
    {
        saveFile(this.files[0]);
    });
});

function saveFile(file)
{
    var fileReader = new FileReader();

    fileReader.onload = function(event)
    {
        var fileAsDataUrl = event.target.result;

        localStorage.setItem('myFile', fileAsDataUrl);
    };

    fileReader.readAsDataURL(file);
}

Kurze Erklärung zum Code:

Zeile 1 – 7
Sobald das DOM der Webseite fertig geladen ist, wird ein Event-Handler für das change-Event des chooseFile-Elements erstellt.

Zeile 11
Eine neue Instanz der FileReader-Klasse erstellen.

Zeile 13
Da die FileReader-Klasse asynchron arbeitet, implementieren wir den onload-Event-Handler. Dieser wird aufgerufen sobald die Datei fertig eingelesen wurde.

Zeile 15
Den als Data-URL eingelesenen Dateiinhalt können wir per event.target.result abrufen.

Zeile 17
Speichern der Datei bzw. des kodierten Dateiinhalts.

Zeile 20
Den asynchronen Vorgang zum Einlesen der Datei starten.

Zum Überprüfen, ob die Datei auch wirklich gespeichert wurde, könnt ihr bei Firefox z.B. Firebug nutzen. In der Firebug-Konsole einfach localStorage eingeben und dann werden euch alle gespeicherten Schlüssel-Wert-Paare angezeigt.

Je nach eurer gespeicherten Datei, sieht der Eintrag im LocalStorage dann etwa so aus:

data:application/pdf;base64,JVBERi0xLjUKJdDUxdgKMSAwIG9iago8PCAvUyAvR2

Datei auslesen und anzeigen

Nun nützt uns eine gespeicherte Datei nicht viel, wenn wir sie nicht auch wieder auslesen können. Dazu erstellen wir uns als erstes einen weiteren Event-Handler für unsere showFile-Schaltfläche:

$(document).ready(function()
{
    $('#chooseFile').bind('change', function()
    {
        saveFile(this.files[0]);
    });

    $('#showFile').bind('click', function()
    {
        showFile();
    });
});

Als nächstes implementieren wir die showFile-Funktion:

function showFile()
{
    var fileAsDataUrl = localStorage.getItem('myFile');
    var fileData = fileAsDataUrl.split(',');
	
    fileAsDataUrl = window.atob(fileData[1]);
    var contentType = (fileData[0].split(':')[1]).split(';')[0];
	
    var uInt8Array = new Uint8Array(fileAsDataUrl.length);

    for(var i = 0; i < fileAsDataUrl.length; ++i)
    {
        uInt8Array[i] = fileAsDataUrl.charCodeAt(i);
    }

    var fileAsBlob = new Blob([uInt8Array], {'type': contentType});

    $('iframe').attr('src', window.URL.createObjectURL(fileAsBlob));
}

Dazu wieder eine kurze Erklärung:

Zeile 3
Auslesen des gespeicherten Dateiinhalts.

Zeile 4
Wir „splitten“ den Data-URL-String in zwei Teile und zwar in den Content-Type und eigentlichen Inhalt der Datei.

Zeile 6
Mittels der atob-Funktion dekodieren wir den base64-kodierten Dateiinhalt.

Zeile 7
Der Stringteil der den Content-Type enthält, muss noch ein wenig angepasst werden. Im Moment ist der String nämlich wie folgt aufgebaut: data:contentType;base64. Aus diesem Grund extrahieren wir den Mittelteil, um wirklich den Content-Type zu erhalten.

Zeile 9
Erstellen einer neuen Instanz der Uint8Array-Klasse.

Zeile 11 – 14
Füllen des speziellen Uint8Array-Objekts.

Zeile 16
Den Dateiinhalt in den Datentyp Blob umwandeln. Dazu erstellen wir eine neue Blob-Instanz und übergeben das Uint8Array-Objekt und den Content-Type.

Zeile 18
Mittels der window.URL.createObjectURL-Funktion genrieren wir eine spezielle Objekt-URL, die unseren Dateiinhalt referenziert. Die generierte Objekt-URL setzen wir als src des iFrames.

Nach einem Klick auf die „Datei anzeigen“-Schaltfläche wird so der Dateiinhalt unserer gespeicherten Datei im iFrame angezeigt.

Fazit

Unabhängig davon, dass eigentlich nur Werte vom Typ DOMString mittels der WebStorage API gespeichert werden können, lassen sich auch Dateien nach einer einfachen Umwandlung via File API speichern.

Letztendlich macht es aber aufgrund des geringen Speicherlimits von ca. 5MB natürlich nur bedingt Sinn Dateien im WebStorage des Webbrowsers zu speichern.

Kommentare  
2 Kommentare vorhanden
1 JonasB schrieb am 10. Mai 2013 um 17:55 Uhr

Schon eine coole Sache, auch wenn mir spontan kein Anwendungsfall dafür einfällt. Hattest du da einen konkreten Fall, oder wie bist du auf den Artikel gekommen?

2 Stephan L. schrieb am 13. Mai 2013 um 11:42 Uhr

Hallo Jonas,

konkrete Anwendungsfälle Dateien im WebStorage zu speichern fallen mir auch keine ein. Liegt vor allem an dem geringen Speicherlimit und der Beschränkung des Datentyps auf DOMString.

Generell gibt es aber schon Anwendungsfälle, wo es Sinn machen kann, Dateien lokal zu speichern:

– Datei-Upload: Um größere Dateien oder sogar ganze Verzeichnisse hochzuladen. So können die vom Nutzer ausgewählten Dateien erst mal im lokalen Speicher des Webbrowser (via IndexedDB API oder FileSystem API) zwischengespeichert und dann sukzessive in Chunks zum Server gesendet werden. Hätte die Möglichkeit, dass du den Upload auch unterbrechen kannst und zum späteren Zeitpunkt fortsetzen könntest.
– Online-Bildeditoren: anstatt Bilder unnötig zum Server hochzuladen, einfach lokal im Webbrowser speichern, zu mal die meiste Funktionalität, was Bildbearbeitung angeht, sowieso im Client mittels JavaScript implementiert ist
– generell für den Offline-Betrieb von Webapplikationen in Verbindung mit der Application Cache API, wie z.B. bei Web-Mail-Clients, wo man die Mails dann clientseitig speichern und somit auch Offline durchsuchen, betrachten, vorschreiben könnte (was Google mit Gmail ja glaube ich schon längere Zeit ermöglicht)
– …

Auf die Idee, Dateien im WebStorage zu speichern, bin ich im Rahmen meiner Masterarbeit gekommen. Derzeit evaluiere ich gerade die verschiedenen Möglichkeiten Daten (Dateien inbegriffen) clientseitig im Webbrowser auf Basis von HTML5 zu speichern.

Diesbezüglich werden in den nächsten Wochen wohl weitere HTML5-lastige Artikel folgen. Vorwiegende Themen sind dann IndexedDB API, File & FileSystem API, Application Cache API und Web Worker API.

Grüße

Stephan

0 Trackbacks/Pingbacks vorhanden
Du bist herzlich eingeladen auch ein Kommentar zu hinterlassen!
Kommentar schreiben

Vielen Dank für dein Kommentar!