Dateien in JavaScript lesen

Das Auswählen von Dateien auf dem lokalen Gerät des Nutzers und die Interaktion mit diesen Dateien ist eine der am häufigsten verwendeten Funktionen des Internets. Damit können Nutzer Dateien auswählen und auf einen Server hochladen, z. B. wenn sie Fotos teilen oder Steuerunterlagen einreichen. Außerdem können Websites die Daten lesen und bearbeiten, ohne sie über das Netzwerk übertragen zu müssen. Auf dieser Seite wird beschrieben, wie Sie mit JavaScript mit Dateien interagieren.

Die moderne File System Access API

Die File System Access API bietet eine Möglichkeit, Dateien und Verzeichnisse auf dem lokalen System des Nutzers zu lesen und zu 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, einer Hilfsbibliothek, die die neue API verwendet, sofern sie verfügbar ist, und ansonsten auf Legacy-Ansätze zurückgreift.

Mit Dateien arbeiten – die klassische Methode

In diesem Leitfaden erfahren Sie, wie Sie mit Legacy-JavaScript-Methoden mit Dateien interagieren.

Dateien auswählen

Es gibt zwei primäre Möglichkeiten, Dateien auszuwählen: über das HTML-Eingabeelement und über eine Drag-and-drop-Zone.

HTML-Eingabeelement

Am einfachsten können Nutzer Dateien über das Element <input type="file"> auswählen, das in allen wichtigen Browsern unterstützt wird. Wenn ein Nutzer darauf klickt, kann er eine oder mehrere Dateien auswählen, wenn das Attribut multiple enthalten ist. Dazu wird die integrierte Benutzeroberfläche zur Dateiauswahl des Betriebssystems verwendet. Wenn der Nutzer die Auswahl einer oder mehrerer Dateien abgeschlossen hat, wird das change-Ereignis des Elements ausgelöst. Sie können über event.target.files auf die Liste der Dateien zugreifen. event.target.files ist ein FileList-Objekt. Jedes Element in 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 mehrere Dateien über die integrierte Benutzeroberfläche zur Dateiauswahl des Betriebssystems auswählen. Anschließend wird jede ausgewählte Datei in der Konsole protokolliert.

Einschränken, welche Dateitypen Nutzer auswählen können

In einigen Fällen möchten Sie möglicherweise die Dateitypen einschränken, die Nutzer auswählen können. Eine Bildbearbeitungs-App sollte beispielsweise nur Bilder und keine Textdateien akzeptieren. Wenn Sie Einschränkungen für Dateitypen festlegen möchten, fügen Sie dem Eingabeelement ein accept-Attribut 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 Ablageziel, sodass Nutzer Dateien per Drag-and-drop in Ihre App ziehen können. Dieses Ablageziel ist jedoch klein und kann schwer zu verwenden sein. Stattdessen können Sie nach der Bereitstellung von Kernfunktionen über ein <input type="file">-Element eine große, benutzerdefinierte Drag-and-drop-Oberfläche bereitstellen.

Abwurfzone auswählen

Die Drop-Oberfläche hängt vom Design Ihrer Anwendung ab. Möglicherweise soll nur ein Teil des Fensters als Ablagefläche dienen, aber Sie können das gesamte Fenster verwenden.

Ein Screenshot von Squoosh, einer Web-App zur Bildkomprimierung.
In Squoosh wird das gesamte Fenster zu einer Ablagezone.

In der Bildkomprimierungs-App Squoosh können Nutzer ein Bild an eine beliebige Stelle im Fenster ziehen und auf Bild auswählen klicken, um das <input type="file">-Element aufzurufen. Unabhängig davon, welche Drop-Zone Sie auswählen, muss für den Nutzer klar sein, dass er Dateien auf diese Oberfläche ziehen kann.

Abwurfzone definieren

Wenn Sie ein Element als Drag-and-drop-Bereich aktivieren möchten, erstellen Sie Listener für zwei Ereignisse: dragover und drop. Das dragover-Ereignis aktualisiert die Browser-Benutzeroberfläche, um visuell anzuzeigen, dass durch das Drag-and-drop-Verfahren 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 auf die Liste der Dateien zugreifen. Dabei handelt es sich um ein FileList-Objekt. Jedes Element in 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() verhindern das Standardverhalten des Browsers und lassen stattdessen Ihren Code ausführen. Andernfalls würde der Browser Ihre Seite verlassen und die Dateien öffnen, die der Nutzer in das Browserfenster gezogen hat.

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

Was ist mit Verzeichnissen?

Leider gibt es keine gute Möglichkeit, mit 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, mit Ausnahme von Firefox für Android und Safari unter iOS.

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

Dateimetadaten lesen

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

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});
  }
}

input-type-file Demo ansehen

Inhalte einer Datei lesen

Verwenden Sie FileReader, um den Inhalt eines File-Objekts in den Arbeitsspeicher zu lesen. Sie können FileReader anweisen, eine Datei als Array-Buffer, 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 ein File gelesen, das vom Nutzer bereitgestellt wird, dann in eine Daten-URL konvertiert und diese Daten-URL verwendet, um das Bild in einem img-Element anzuzeigen. Informationen dazu, wie Sie überprüfen, ob der Nutzer eine Bilddatei ausgewählt hat, finden Sie in der read-image-file-Demo.

Fortschritt beim Lesen einer Datei überwachen

Beim Lesen großer Dateien kann es hilfreich sein, dem Nutzer über die Benutzeroberfläche mitzuteilen, wie weit der Lesevorgang fortgeschritten ist. Verwenden Sie dazu das Ereignis progress, das von FileReader bereitgestellt wird. Das Ereignis progress hat zwei Attribute: loaded (gelesene Menge) und total (zu lesende Menge).

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