Dateien in JavaScript lesen

Die Auswahl von Dateien und die Interaktion mit Dateien auf dem lokalen Gerät des Nutzers ist eine der am häufigsten verwendeten Funktionen im Web. Nutzer können damit Dateien auswählen und auf einen Server hochladen, um beispielsweise Fotos zu teilen oder Steuerdokumente einzureichen. Außerdem können Websites sie lesen und bearbeiten, ohne die Daten über das Netzwerk übertragen zu müssen. Auf dieser Seite wird beschrieben, wie Sie JavaScript für die Interaktion mit Dateien verwenden.

Die moderne File System Access API

Mit der File System Access API können Sie Daten aus Dateien und Verzeichnissen auf dem lokalen System des Nutzers lesen und in diese schreiben. Sie ist in den meisten Chromium-basierten Browsern wie Chrome und Edge verfügbar. Weitere Informationen finden Sie unter File System Access API.

Da die File System Access API nicht mit allen Browsern kompatibel ist, empfehlen wir die Verwendung von browser-fs-access. Diese Hilfsbibliothek verwendet die neue API, sobald sie verfügbar ist, und auf Legacy-Ansätze zurückgreift, wenn dies nicht der Fall ist.

Mit Dateien arbeiten wie gewohnt

In diesem Leitfaden erfahren Sie, wie Sie über alte JavaScript-Methoden mit Dateien interagieren.

Dateien auswählen

Es gibt zwei Möglichkeiten, Dateien auszuwählen: mithilfe des HTML-Eingabeelements oder mithilfe einer Drag-and-drop-Zone.

HTML-Eingabeelement

Nutzer können Dateien am einfachsten mit dem Element <input type="file"> auswählen, das von allen gängigen Browsern unterstützt wird. Wenn ein Nutzer darauf klickt, kann er über die integrierte Benutzeroberfläche zur Dateiauswahl seines Betriebssystems eine oder mehrere Dateien auswählen, sofern das Attribut multiple enthalten ist. Wenn der Nutzer eine oder mehrere Dateien ausgewählt hat, wird das Ereignis change des Elements ausgelöst. Sie können über event.target.files auf die Liste der Dateien zugreifen. Dabei handelt es sich um ein FileList-Objekt. Jedes Element im FileList ist ein File-Objekt.

<!-- The `multiple` attribute lets users select multiple files. -->
<input type="file" id="file-selector" multiple>
<script>
  const fileSelector = document.getElementById('file-selector');
  fileSelector.addEventListener('change', (event) => {
    const fileList = event.target.files;
    console.log(fileList);
  });
</script>

Im folgenden Beispiel kann ein Nutzer über die integrierte Benutzeroberfläche zur Dateiauswahl des Betriebssystems mehrere Dateien auswählen und dann jede ausgewählte Datei in der Konsole protokollieren.

Dateitypen einschränken, die Nutzer auswählen können

In manchen Fällen kann es sinnvoll sein, die Dateitypen einzuschränken, die Nutzer auswählen können. Eine Bildbearbeitungsanwendung sollte beispielsweise nur Bilder akzeptieren, keine Textdateien. Zum Festlegen von Einschränkungen für Dateitypen fügen Sie dem Eingabeelement das Attribut accept hinzu, um anzugeben, welche Dateitypen akzeptiert werden:

<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">

Benutzerdefiniertes Drag-and-drop

In einigen Browsern ist das <input type="file">-Element auch ein Drop-Ziel, mit dem Nutzer Dateien per Drag-and-drop in Ihre Anwendung ziehen können. Dieses Drop-Ziel ist jedoch klein und kann schwierig zu verwenden sein. Nachdem Sie Hauptfunktionen mithilfe eines <input type="file">-Elements bereitgestellt haben, können Sie stattdessen eine große, benutzerdefinierte Drag-and-drop-Oberfläche bereitstellen.

Drop-Zone auswählen

Die Falloberfläche hängt vom Design der App ab. Auch wenn nur ein Teil des Fensters eine Ablagefläche sein soll, können Sie das gesamte Fenster verwenden.

Screenshot von Squoosh, einer Web-App für die Bildkomprimierung.
Squoosh macht das gesamte Fenster zu einer Drop-Zone.

Mit der Bildkomprimierungsanwendung Squoosh können Nutzer ein Bild an eine beliebige Stelle in das Fenster ziehen und auf Bild auswählen klicken, um das Element <input type="file"> aufzurufen. Egal, was du als Zone auswählst, achte darauf, dass für Nutzer klar erkennbar ist, dass sie Dateien auf diese Oberfläche ziehen können.

Drop-Zone definieren

Wenn Sie ein Element als Drag-and-drop-Zone aktivieren möchten, müssen Sie Listener für zwei Ereignisse erstellen: dragover und drop. Mit dem Ereignis dragover wird die Benutzeroberfläche des Browsers aktualisiert, um visuell anzuzeigen, dass mit der Drag-and-drop-Aktion eine Kopie der Datei erstellt wird. Das Ereignis drop wird ausgelöst, nachdem der Nutzer die Dateien auf der Oberfläche abgelegt hat. Wie beim Eingabeelement können Sie über event.dataTransfer.files, ein FileList-Objekt, auf die Liste der Dateien zugreifen. Jedes Element im FileList ist ein File-Objekt.

const dropArea = document.getElementById('drop-area');

dropArea.addEventListener('dragover', (event) => {
  event.stopPropagation();
  event.preventDefault();
  // Style the drag-and-drop as a "copy file" operation.
  event.dataTransfer.dropEffect = 'copy';
});

dropArea.addEventListener('drop', (event) => {
  event.stopPropagation();
  event.preventDefault();
  const fileList = event.dataTransfer.files;
  console.log(fileList);
});

event.stopPropagation() und event.preventDefault() stoppen das Standardverhalten des Browsers und lassen stattdessen Ihren Code ausführen. Andernfalls würde der Browser die Seite verlassen und die Dateien öffnen, die der Nutzer im Browserfenster geöffnet hat.

Eine Live-Demo finden Sie unter Benutzerdefiniertes Drag-and-drop.

Was ist mit Verzeichnissen?

Leider gibt es keine gute Möglichkeit, mithilfe von JavaScript auf ein Verzeichnis zuzugreifen.

Mit dem Attribut webkitdirectory für das Element <input type="file"> kann der Nutzer ein oder mehrere Verzeichnisse auswählen. Sie wird in den meisten gängigen Browsern unterstützt, außer in Firefox für Android und Safari unter iOS.

Wenn Drag-and-drop aktiviert ist, versucht ein Nutzer möglicherweise, ein Verzeichnis in die Drop-Zone zu ziehen. Wenn das Drop-Ereignis ausgelöst wird, enthält es ein File-Objekt für das Verzeichnis, bietet jedoch keinen Zugriff auf die Dateien im Verzeichnis.

Dateimetadaten lesen

Das Objekt File enthält Metadaten zur Datei. Die meisten Browser geben den Dateinamen, die Größe der Datei und den MIME-Typ an. Je nach Plattform können jedoch unterschiedliche Browser unterschiedliche oder zusätzliche Informationen bereitstellen.

function getMetadataForFileList(fileList) {
  for (const file of fileList) {
    // Not supported in Safari for iOS.
    const name = file.name ? file.name : 'NOT SUPPORTED';
    // Not supported in Firefox for Android or Opera for Android.
    const type = file.type ? file.type : 'NOT SUPPORTED';
    // Unknown cross-browser support.
    const size = file.size ? file.size : 'NOT SUPPORTED';
    console.log({file, name, type, size});
  }
}

Ein Beispiel dafür finden Sie in der input-type-file-Demo.

Dateiinhalt lesen

Verwenden Sie FileReader, um den Inhalt eines File-Objekts in den Arbeitsspeicher zu lesen. Sie können FileReader anweisen, eine Datei als Arrayzwischenspeicher, Daten-URL oder Text zu lesen:

function readImage(file) {
  // Check if the file is an image.
  if (file.type && !file.type.startsWith('image/')) {
    console.log('File is not an image.', file.type, file);
    return;
  }

  const reader = new FileReader();
  reader.addEventListener('load', (event) => {
    img.src = event.target.result;
  });
  reader.readAsDataURL(file);
}

In diesem Beispiel wird eine vom Nutzer bereitgestellte File gelesen, dann in eine Daten-URL umgewandelt und diese Daten-URL verwendet, um das Bild in einem img-Element anzuzeigen. Informationen dazu, wie du prüfen kannst, ob der Nutzer eine Bilddatei ausgewählt hat, findest du in der read-image-file-Demo.

Fortschritt eines Dateilesevorgangs überwachen

Beim Lesen großer Dateien kann es hilfreich sein, Nutzern etwas UX-Design bereitzustellen, um zu erkennen, wie weit der Lesevorgang bereits fortgeschritten ist. Verwenden Sie dazu das von FileReader bereitgestellte Ereignis progress. Das progress-Ereignis hat zwei Eigenschaften: loaded (die gelesene Menge) und total (der zu lesende Wert).

function readFile(file) {
  const reader = new FileReader();
  reader.addEventListener('load', (event) => {
    const result = event.target.result;
    // Do something with result
  });

  reader.addEventListener('progress', (event) => {
    if (event.loaded && event.total) {
      const percent = (event.loaded / event.total) * 100;
      console.log(`Progress: ${Math.round(percent)}`);
    }
  });
  reader.readAsDataURL(file);
}

Hero-Image von Vincent Botta von Unsplash