Lire des fichiers en JavaScript

Sélectionner des fichiers et interagir avec eux sur l'appareil local de l'utilisateur est l'une des fonctionnalités les plus couramment utilisées sur le Web. Elle permet aux utilisateurs de sélectionner des fichiers et de les importer sur un serveur, par exemple lorsqu'ils partagent des photos ou envoient des documents fiscaux. Il permet également aux sites de les lire et de les manipuler sans jamais avoir à transférer les données sur le réseau. Cette page explique comment utiliser JavaScript pour interagir avec des fichiers.

API moderne File System Access

L'API File System Access permet de lire et d'écrire dans des fichiers et des répertoires sur le système local de l'utilisateur. Elle est disponible dans la plupart des navigateurs basés sur Chromium, comme Chrome et Edge. Pour en savoir plus, consultez la page API File System Access.

Étant donné que l'API File System Access n'est pas compatible avec tous les navigateurs, nous vous recommandons d'utiliser browser-fs-access, une bibliothèque d'aide qui utilise la nouvelle API partout où elle est disponible et qui se rabat sur les anciennes approches lorsque ce n'est pas le cas.

Travailler avec des fichiers de façon classique

Ce guide vous explique comment interagir avec les fichiers à l'aide d'anciennes méthodes JavaScript.

Sélectionner des fichiers

Il existe deux méthodes principales pour sélectionner des fichiers: à l'aide de l'élément d'entrée HTML et à l'aide d'une zone par glisser-déposer.

Élément d'entrée HTML

Le moyen le plus simple pour les utilisateurs de sélectionner des fichiers consiste à utiliser l'élément <input type="file">, qui est compatible avec tous les principaux navigateurs. Lorsqu'un utilisateur clique dessus, il peut sélectionner un ou plusieurs fichiers si l'attribut multiple est inclus, à l'aide de l'interface utilisateur de sélection de fichiers intégrée au système d'exploitation. Lorsque l'utilisateur a fini de sélectionner un ou plusieurs fichiers, l'événement change de l'élément se déclenche. Vous pouvez accéder à la liste des fichiers à partir de event.target.files, qui est un objet FileList. Chaque élément de FileList est un objet File.

<!-- 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>

L'exemple suivant permet à un utilisateur de sélectionner plusieurs fichiers à l'aide de l'interface utilisateur de sélection de fichiers intégrée à son système d'exploitation, puis d'enregistrer chaque fichier sélectionné dans la console.

Limiter les types de fichiers que les utilisateurs peuvent sélectionner

Dans certains cas, vous souhaiterez peut-être limiter les types de fichiers que les utilisateurs peuvent sélectionner. Par exemple, une application de retouche d'images ne doit accepter que des images, et non des fichiers texte. Pour définir des restrictions de type de fichier, ajoutez un attribut accept à l'élément d'entrée afin de spécifier les types de fichiers acceptés:

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

Glisser-déposer personnalisé

Dans certains navigateurs, l'élément <input type="file"> est également une cible de dépôt, ce qui permet aux utilisateurs de glisser-déposer des fichiers dans votre application. Cependant, cette cible de dépôt est petite et peut être difficile à utiliser. À la place, après avoir fourni les fonctionnalités de base à l'aide d'un élément <input type="file">, vous pouvez fournir une grande surface de glisser-déposer personnalisée.

Choisissez votre zone de dépôt

La surface de dépôt dépend de la conception de votre application. Si vous souhaitez qu'une partie de la fenêtre ne soit qu'une surface de chute, vous pouvez l'utiliser dans son intégralité.

Capture d&#39;écran de Squoosh, une application Web de compression d&#39;images
Squoosh transforme la fenêtre entière en zone de dépôt.

L'application de compression d'images Squoosh permet à l'utilisateur de faire glisser une image n'importe où dans la fenêtre, puis de cliquer sur select an image (sélectionner une image) pour appeler l'élément <input type="file">. Quelle que soit la zone que vous choisissez, assurez-vous que l'utilisateur peut faire glisser des fichiers sur cette surface.

Définir la zone de dépôt

Pour activer un élément en tant que zone de glisser-déposer, créez des écouteurs pour deux événements: dragover et drop. L'événement dragover met à jour l'interface utilisateur du navigateur pour indiquer visuellement que l'action glisser-déposer crée une copie du fichier. L'événement drop se déclenche lorsque l'utilisateur a déposé les fichiers sur la surface. Comme pour l'élément d'entrée, vous pouvez accéder à la liste des fichiers à partir de event.dataTransfer.files, qui est un objet FileList. Chaque élément de FileList est un objet File.

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() et event.preventDefault() désactivent le comportement par défaut du navigateur et laissent votre code s'exécuter à la place. Sans elles, le navigateur quitterait votre page et ouvrirait les fichiers que l'utilisateur a déposés dans la fenêtre du navigateur.

Pour voir une démonstration en direct, consultez Glisser-déposer personnalisé.

Qu'en est-il des répertoires ?

Malheureusement, il n'existe pas de bon moyen d'accéder à un répertoire en utilisant JavaScript.

L'attribut webkitdirectory de l'élément <input type="file"> permet à l'utilisateur de choisir un ou plusieurs répertoires. Elle est compatible avec la plupart des principaux navigateurs, à l'exception de Firefox pour Android et de Safari sous iOS.

Si le glisser-déposer est activé, un utilisateur peut essayer de faire glisser un répertoire dans la zone de dépôt. Lorsque l'événement de suppression se déclenche, il inclut un objet File pour le répertoire, mais ne fournit l'accès à aucun des fichiers du répertoire.

Lire les métadonnées du fichier

L'objet File contient des métadonnées sur le fichier. La plupart des navigateurs fournissent le nom de fichier, la taille du fichier et le type MIME. Toutefois, selon la plate-forme, différents navigateurs peuvent fournir des informations différentes ou supplémentaires.

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

Vous pouvez voir cela en action dans la démonstration de input-type-file.

Lire le contenu d'un fichier

Utilisez FileReader pour lire le contenu d'un objet File en mémoire. Vous pouvez demander à FileReader de lire un fichier sous forme de tampon de tableau, d'URL de données ou de texte:

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

Cet exemple lit un File fourni par l'utilisateur, puis le convertit en URL de données et utilise cette URL de données pour afficher l'image dans un élément img. Pour savoir comment vérifier que l'utilisateur a sélectionné un fichier image, consultez la démonstration de read-image-file.

Surveiller la progression de la lecture d'un fichier

Lors de la lecture de fichiers volumineux, il peut être utile de fournir une expérience utilisateur pour indiquer à l'utilisateur la progression de la lecture. Pour ce faire, utilisez l'événement progress fourni par FileReader. L'événement progress possède deux propriétés : loaded (quantité lue) et total (quantité à lire).

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

Image principale par Vincent Botta, tirée de la série Unsplash