La sélection et l'interaction avec des fichiers sur l'appareil local de l'utilisateur est l'une des fonctionnalités les plus couramment utilisées sur le Web. Il permet aux utilisateurs de sélectionner des fichiers et de les importer sur un serveur, par exemple lors du partage de photos ou de l'envoi de documents fiscaux. Il permet également aux sites de les lire et de les manipuler sans avoir à transférer les données sur le réseau. Cette page explique comment utiliser JavaScript pour interagir avec des fichiers.
L'API File System Access moderne
L'API File System Access permet de lire et d'écrire des fichiers et des répertoires sur le système local de l'utilisateur. Elle est disponible dans la plupart des navigateurs Chromium, tels que 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'assistance qui utilise la nouvelle API partout où elle est disponible et qui revient aux anciennes approches lorsqu'elle ne l'est pas.
Travailler avec des fichiers de la manière classique
Ce guide vous explique comment interagir avec des fichiers à l'aide d'anciennes méthodes JavaScript.
Sélectionner des fichiers
Il existe deux principales façons de sélectionner des fichiers: à l'aide de l'élément d'entrée HTML et à l'aide d'une zone de 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. Lorsque l'utilisateur clique dessus, il peut sélectionner un fichier ou plusieurs fichiers si l'attribut multiple
est inclus, à l'aide de l'interface utilisateur de sélection de fichiers intégrée à son système d'exploitation. Lorsque l'utilisateur a terminé 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'UI de sélection de fichiers intégrée de son système d'exploitation, puis de consigner chaque fichier sélectionné dans la console.
Limiter les types de fichiers que les utilisateurs peuvent sélectionner
Dans certains cas, vous pouvez souhaiter limiter les types de fichiers que les utilisateurs peuvent sélectionner. Par exemple, une application de retouche d'image 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 de saisie pour 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. Toutefois, cette cible de dépôt est petite et peut être difficile à utiliser. Au lieu de cela, 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.
Choisir votre zone de dépôt
La surface de dépôt dépend de la conception de votre application. Vous ne souhaitez peut-être qu'une partie de la fenêtre soit une surface de dépôt, mais vous pouvez utiliser l'intégralité de la fenêtre.
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 Sélectionner une image pour appeler l'élément <input type="file">
. Quelle que soit la zone de dépôt que vous choisissez, assurez-vous que l'utilisateur comprend clairement qu'il peut y faire glisser des fichiers.
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'UI du navigateur pour indiquer visuellement que l'action de glisser-déposer crée une copie du fichier. L'événement drop
se déclenche une fois que l'utilisateur a déposé les fichiers sur la surface. Comme pour l'élément input, 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()
arrêtent le comportement par défaut du navigateur et permettent à votre code de 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 obtenir 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 à l'aide de JavaScript.
L'attribut webkitdirectory
de l'élément <input type="file">
permet à l'utilisateur de choisir un ou plusieurs répertoires. Il est compatible avec la plupart des principaux navigateurs, à l'exception de Firefox pour Android et Safari sur 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 dépôt se déclenche, il inclut un objet File
pour le répertoire, mais n'offre aucun accès aux fichiers du répertoire.
Lire les métadonnées des fichiers
L'objet File
contient des métadonnées sur le fichier. La plupart des navigateurs fournissent le nom du fichier, sa taille et le type MIME. Toutefois, selon la plate-forme, les 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 ce comportement dans la démonstration de input-type-file
.
Lire le contenu d'un fichier
Utilisez FileReader
pour lire le contenu d'un objet File
dans la mémoire. Vous pouvez demander à FileReader
de lire un fichier en tant que tampon de tableau, une URL de données ou un 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 read-image-file
.
Surveiller la progression de la lecture d'un fichier
Lorsque vous lisez de gros fichiers, il peut être utile de fournir une expérience utilisateur pour indiquer à l'utilisateur l'avancement de la lecture. Pour ce faire, utilisez l'événement progress
fourni par FileReader
. L'événement progress
comporte 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 sur Unsplash