API File System Access: simplifier l'accès aux fichiers locaux

L'API File System Access permet aux applications Web de lire ou d'enregistrer les modifications directement dans les fichiers et les dossiers de l'appareil de l'utilisateur.

Qu'est-ce que l'API File System Access ?

L'API File System Access permet aux développeurs de créer des applications Web performantes qui interagissent avec les fichiers sur l'appareil local de l'utilisateur, tels que les IDE, les éditeurs de photos et de vidéos, les éditeurs de texte, etc. Après lorsqu'un utilisateur autorise l'accès à une application Web, cette API lui permet de lire ou d'enregistrer les modifications directement dans les fichiers et dossiers sur l'appareil de l'utilisateur. Outre la lecture et l'écriture de fichiers, l'API File System Access fournit la possibilité d'ouvrir un répertoire et d'énumérer son contenu.

Si vous avez déjà travaillé avec la lecture et l'écriture de fichiers, ce que je vais partager sera principalement que vous connaissez déjà. Je vous encourage quand même à le lire, car tous les systèmes ne se ressemblent pas.

L'API File System Access est compatible avec la plupart des navigateurs Chromium sur Windows, macOS, ChromeOS et Linux. Une exception notable est Brave : actuellement disponibles avec un drapeau. La compatibilité avec Android est en cours d'examen par le biais de crbug.com/1011535.

Utiliser l'API File System Access

Pour démontrer la puissance et l'utilité de l'API File System Access, j'ai écrit un seul fichier texte éditeur. Il vous permet d'ouvrir un fichier texte, de le modifier, d'enregistrer les modifications sur le disque ou de commencer un nouveau fichier et enregistrer les modifications sur le disque. Il n'a rien d'extraordinaire, mais il offre suffisamment d'options pour vous aider pour comprendre les concepts.

Prise en charge des navigateurs

Navigateurs pris en charge

  • Chrome: 86 <ph type="x-smartling-placeholder">
  • Edge: 86 <ph type="x-smartling-placeholder">
  • Firefox: non compatible. <ph type="x-smartling-placeholder">
  • Safari: non compatible. <ph type="x-smartling-placeholder">

Source

Détection de caractéristiques

Pour savoir si l'API File System Access est compatible, vérifiez si la méthode de sélection qui vous intéresse existe.

if ('showOpenFilePicker' in self) {
  // The `showOpenFilePicker()` method of the File System Access API is supported.
}

Essayer

Découvrez l'API File System Access en action dans le text Editor (éditeur de texte) de votre site Web.

Lire un fichier à partir du système de fichiers local

Le premier cas d'utilisation que je veux aborder est de demander à l'utilisateur de choisir un fichier, puis de l'ouvrir et de le lire à partir du disque.

Demander à l'utilisateur de choisir un fichier à lire

Le point d'entrée de l'API File System Access est window.showOpenFilePicker() Lorsqu'elle est appelée, elle affiche une boîte de dialogue de sélection de fichier, et invite l'utilisateur à sélectionner un fichier. Une fois le fichier sélectionné, l'API renvoie un tableau de fichiers poignées. Un paramètre options facultatif vous permet d'influencer le comportement de l'outil de sélection de fichier, par exemple par exemple, en permettant à l'utilisateur de sélectionner plusieurs fichiers, répertoires ou différents types de fichiers. Si aucune option n'est spécifiée, le sélecteur de fichier permet à l'utilisateur de sélectionner un seul fichier. C'est parfait pour un éditeur de texte.

Comme de nombreuses autres API performantes, l'appel de showOpenFilePicker() doit s'effectuer de manière sécurisée le contexte, et doivent être appelées à partir d'un geste de l'utilisateur.

let fileHandle;
butOpenFile.addEventListener('click', async () => {
  // Destructure the one-element array.
  [fileHandle] = await window.showOpenFilePicker();
  // Do something with the file handle.
});

Une fois que l'utilisateur a sélectionné un fichier, showOpenFilePicker() renvoie un tableau de handle, dans ce cas, un tableau à un élément avec un FileSystemFileHandle contenant les propriétés et nécessaires pour interagir avec le fichier.

Il est utile de garder une référence au gestionnaire de fichier afin de pouvoir l'utiliser ultérieurement. Ce sera nécessaire pour enregistrer les modifications apportées au fichier ou pour effectuer toute autre opération sur le fichier.

Lire un fichier à partir du système de fichiers

Maintenant que vous disposez d'un handle vers un fichier, vous pouvez obtenir ses propriétés ou accéder au fichier lui-même. Pour l’instant, je vais lire son contenu. L'appel de handle.getFile() renvoie un File , qui contient un blob. Pour récupérer les données de l'objet blob, appelez l'une de ses méthodes, (slice(), stream(), text() ou arrayBuffer()).

const file = await fileHandle.getFile();
const contents = await file.text();

L'objet File renvoyé par FileSystemFileHandle.getFile() n'est lisible que si le le fichier sous-jacent sur le disque n’a pas changé. Si le fichier sur le disque est modifié, l'objet File devient illisible et vous devrez appeler à nouveau getFile() pour obtenir un nouvel objet File permettant de lire les modifications données.

Synthèse

Lorsque les utilisateurs cliquent sur le bouton Ouvrir, le navigateur affiche un sélecteur de fichier. Une fois qu'ils ont sélectionné un fichier, l'application lit le contenu et le place dans un <textarea>.

let fileHandle;
butOpenFile.addEventListener('click', async () => {
  [fileHandle] = await window.showOpenFilePicker();
  const file = await fileHandle.getFile();
  const contents = await file.text();
  textArea.value = contents;
});

Écrire le fichier dans le système de fichiers local

Dans l'éditeur de texte, vous pouvez enregistrer un fichier de deux façons: Enregistrer et Enregistrer sous. Enregistrer écrit les modifications dans le fichier d'origine à l'aide du traitement de fichier récupéré précédemment. Mais Enregistrer As crée un fichier, ce qui nécessite un nouveau handle de fichier.

Créer un fichier

Pour enregistrer un fichier, appelez showSaveFilePicker(), qui affiche l'outil de sélection de fichier. dans "enregistrer" permettant à l'utilisateur de choisir le nouveau fichier qu'il souhaite utiliser pour l'enregistrement. Pour le texte éditeur, je voulais également qu'il ajoute automatiquement une extension .txt. J'ai donc fourni quelques paramètres.

async function getNewFileHandle() {
  const options = {
    types: [
      {
        description: 'Text Files',
        accept: {
          'text/plain': ['.txt'],
        },
      },
    ],
  };
  const handle = await window.showSaveFilePicker(options);
  return handle;
}

Enregistrer les modifications sur le disque

Vous trouverez tout le code permettant d'enregistrer les modifications apportées à un fichier dans la démo de mon éditeur de texte sur GitHub Les principales interactions du système de fichiers sont fs-helpers.js Dans sa forme la plus simple, le processus se présente comme suit : Je vais passer en revue chaque étape et l'expliquer.

// fileHandle is an instance of FileSystemFileHandle..
async function writeFile(fileHandle, contents) {
  // Create a FileSystemWritableFileStream to write to.
  const writable = await fileHandle.createWritable();
  // Write the contents of the file to the stream.
  await writable.write(contents);
  // Close the file and write the contents to disk.
  await writable.close();
}

L'écriture de données sur le disque utilise un objet FileSystemWritableFileStream, une sous-classe sur WritableStream. Créez le flux en appelant createWritable() sur le fichier handle. Lorsque createWritable() est appelé, le navigateur vérifie d'abord si l'utilisateur a accordé l'autorisation d'écriture sur le fichier. Si l'autorisation d'écriture n'a pas été accordée, le navigateur vous demande à l'utilisateur pour obtenir l'autorisation. Si l'autorisation n'est pas accordée, createWritable() génère une DOMException, et l'application ne pourra pas écrire dans le fichier. Dans l'éditeur de texte, Les objets DOMException sont gérés dans la méthode saveFile().

La méthode write() accepte une chaîne, qui est nécessaire à un éditeur de texte. Mais cela peut aussi prendre un BufferSource ou un Blob. Par exemple, vous pouvez diriger un flux directement vers comme suit:

async function writeURLToFile(fileHandle, url) {
  // Create a FileSystemWritableFileStream to write to.
  const writable = await fileHandle.createWritable();
  // Make an HTTP request for the contents.
  const response = await fetch(url);
  // Stream the response into the file.
  await response.body.pipeTo(writable);
  // pipeTo() closes the destination pipe by default, no need to close it.
}

Vous pouvez également seek() ou truncate() dans le flux pour mettre à jour le à une position spécifique, ou redimensionner le fichier.

Spécification d'un nom de fichier suggéré et d'un répertoire de départ

Dans de nombreux cas, vous souhaiterez peut-être que votre application suggère un nom de fichier ou un emplacement par défaut. Par exemple, un texte l'éditeur peut suggérer le nom de fichier par défaut Untitled Text.txt plutôt que Untitled. Toi Pour ce faire, transmettez une propriété suggestedName dans les options showSaveFilePicker.

const fileHandle = await self.showSaveFilePicker({
  suggestedName: 'Untitled Text.txt',
  types: [{
    description: 'Text documents',
    accept: {
      'text/plain': ['.txt'],
    },
  }],
});

Il en va de même pour le répertoire de départ par défaut. Si vous créez un éditeur de texte, vous voudrez peut-être lancer la boîte de dialogue d'enregistrement ou d'ouverture de fichier dans le dossier documents par défaut, tandis que pour une image, éditeur, vous devriez peut-être commencer dans le dossier par défaut pictures. Vous pouvez suggérer un début par défaut en transmettant une propriété startIn à showSaveFilePicker, showDirectoryPicker() ou showOpenFilePicker comme ceci.

const fileHandle = await self.showOpenFilePicker({
  startIn: 'pictures'
});

Voici la liste des répertoires système connus:

  • desktop: répertoire du bureau de l'utilisateur, le cas échéant
  • documents: répertoire dans lequel les documents créés par l'utilisateur sont généralement stockés.
  • downloads: répertoire dans lequel les fichiers téléchargés sont généralement stockés.
  • music: répertoire dans lequel les fichiers audio sont généralement stockés.
  • pictures: répertoire dans lequel les photos et autres images fixes sont généralement stockées.
  • videos: répertoire dans lequel les vidéos ou les films sont généralement stockés

Outre les répertoires système bien connus, vous pouvez également transmettre un identifiant de fichier ou de répertoire existant en tant que une valeur pour startIn. La boîte de dialogue s'ouvrira alors dans le même répertoire.

// Assume `directoryHandle` is a handle to a previously opened directory.
const fileHandle = await self.showOpenFilePicker({
  startIn: directoryHandle
});

Spécifier l'objectif des différents sélecteurs de fichiers

Parfois, les applications disposent de différents sélecteurs pour des objectifs différents. Par exemple, un texte enrichi peut permettre à l'utilisateur d'ouvrir des fichiers texte, mais également d'importer des images. Par défaut, chaque fichier l'outil de sélection s'ouvrira au dernier emplacement mémorisé. Vous pouvez contourner ce problème en stockant des valeurs id pour chaque type de sélecteur. Si un id est spécifié, l'implémentation du sélecteur de fichier mémorise un d'un répertoire distinct utilisé en dernier pour ce id.

const fileHandle1 = await self.showSaveFilePicker({
  id: 'openText',
});

const fileHandle2 = await self.showSaveFilePicker({
  id: 'importImage',
});

Stocker des descripteurs de fichier ou de répertoire dans IndexedDB

Les gestionnaires de fichiers et de répertoires sont sérialisables, ce qui signifie que vous pouvez enregistrer un fichier ou gestionnaire de répertoire vers IndexedDB, ou appelez postMessage() pour les envoyer entre les mêmes instances racine origine.

L'enregistrement des descripteurs de fichier ou de répertoire dans IndexedDB vous permet de stocker l'état ou de vous souvenir les fichiers ou répertoires sur lesquels un utilisateur travaillait. Cela permet de conserver une liste des éléments récemment ouverts ou modifiés, proposer de rouvrir le dernier fichier à l'ouverture de l'application, restaurer le fichier précédent répertoire, etc. Dans l'éditeur de texte, je stocke la liste des cinq fichiers les plus récents de l'utilisateur ouverts, ce qui permet d’accéder à nouveau à ces fichiers.

L'exemple de code suivant montre comment stocker et récupérer un handle de fichier et un handle de répertoire. Vous pouvez voir ceci sur Glitch. (J'utilise la bibliothèque idb-keyval par souci de concision.)

import { get, set } from 'https://unpkg.com/idb-keyval@5.0.2/dist/esm/index.js';

const pre1 = document.querySelector('pre.file');
const pre2 = document.querySelector('pre.directory');
const button1 = document.querySelector('button.file');
const button2 = document.querySelector('button.directory');

// File handle
button1.addEventListener('click', async () => {
  try {
    const fileHandleOrUndefined = await get('file');
    if (fileHandleOrUndefined) {
      pre1.textContent = `Retrieved file handle "${fileHandleOrUndefined.name}" from IndexedDB.`;
      return;
    }
    const [fileHandle] = await window.showOpenFilePicker();
    await set('file', fileHandle);
    pre1.textContent = `Stored file handle for "${fileHandle.name}" in IndexedDB.`;
  } catch (error) {
    alert(error.name, error.message);
  }
});

// Directory handle
button2.addEventListener('click', async () => {
  try {
    const directoryHandleOrUndefined = await get('directory');
    if (directoryHandleOrUndefined) {
      pre2.textContent = `Retrieved directroy handle "${directoryHandleOrUndefined.name}" from IndexedDB.`;
      return;
    }
    const directoryHandle = await window.showDirectoryPicker();
    await set('directory', directoryHandle);
    pre2.textContent = `Stored directory handle for "${directoryHandle.name}" in IndexedDB.`;
  } catch (error) {
    alert(error.name, error.message);
  }
});

Identifiants et autorisations des fichiers ou répertoires stockés

Étant donné que les autorisations ne sont pas toujours conservées d'une session à l'autre, vous devez vérifier si l'utilisateur a autorisé l'accès au fichier ou au répertoire à l'aide de queryPermission(). Si ce n'est pas le cas, appelez requestPermission() pour la (re)demander. Cela fonctionne de la même manière pour les gestionnaires de fichiers et de répertoires. Toi exécuter fileOrDirectoryHandle.requestPermission(descriptor) ou fileOrDirectoryHandle.queryPermission(descriptor) respectivement.

Dans l'éditeur de texte, j'ai créé une méthode verifyPermission() qui vérifie si l'utilisateur a déjà l'autorisation accordée et, si nécessaire, fait la demande.

async function verifyPermission(fileHandle, readWrite) {
  const options = {};
  if (readWrite) {
    options.mode = 'readwrite';
  }
  // Check if permission was already granted. If so, return true.
  if ((await fileHandle.queryPermission(options)) === 'granted') {
    return true;
  }
  // Request permission. If the user grants permission, return true.
  if ((await fileHandle.requestPermission(options)) === 'granted') {
    return true;
  }
  // The user didn't grant permission, so return false.
  return false;
}

En demandant une autorisation d’écriture avec la requête de lecture, j’ai réduit le nombre d’invites d’autorisation ; l'utilisateur voit une invite à l'ouverture du fichier et accorde l'autorisation de le lire et de l'écrire.

Ouvrir un répertoire et énumérer son contenu

Pour énumérer tous les fichiers d'un répertoire, appelez showDirectoryPicker(). L'utilisateur sélectionne un répertoire dans un sélecteur, après quoi un FileSystemDirectoryHandle est qui vous permet d'énumérer et d'accéder aux fichiers du répertoire. Par défaut, vous avez lu aux fichiers du répertoire, mais si vous avez besoin d'un accès en écriture, vous pouvez transmettre { mode: 'readwrite' } à la méthode.

butDir.addEventListener('click', async () => {
  const dirHandle = await window.showDirectoryPicker();
  for await (const entry of dirHandle.values()) {
    console.log(entry.kind, entry.name);
  }
});

Si vous devez également accéder à chaque fichier à l'aide de getFile() pour, par exemple, obtenir les identifiants tailles de fichier, n'utilisez pas await pour chaque résultat de manière séquentielle, mais traitez plutôt tous les fichiers de parallèle, par exemple, à l'aide de Promise.all().

butDir.addEventListener('click', async () => {
  const dirHandle = await window.showDirectoryPicker();
  const promises = [];
  for await (const entry of dirHandle.values()) {
    if (entry.kind !== 'file') {
      continue;
    }
    promises.push(entry.getFile().then((file) => `${file.name} (${file.size})`));
  }
  console.log(await Promise.all(promises));
});

Créer des fichiers et des dossiers dans un répertoire ou y accéder

À partir d'un répertoire, vous pouvez créer des fichiers et des dossiers, ou y accéder à l'aide de l' getFileHandle() ou getDirectoryHandle() respectivement . En transmettant un objet options facultatif avec une clé de create et une valeur booléenne de true ou false, vous pouvez déterminer si un fichier ou un dossier doit être créé s'il n'existe pas.

// In an existing directory, create a new directory named "My Documents".
const newDirectoryHandle = await existingDirectoryHandle.getDirectoryHandle('My Documents', {
  create: true,
});
// In this new directory, create a file named "My Notes.txt".
const newFileHandle = await newDirectoryHandle.getFileHandle('My Notes.txt', { create: true });

Résoudre le chemin d'accès à un élément d'un répertoire

Lorsque vous travaillez avec des fichiers ou des dossiers dans un répertoire, il peut être utile de résoudre le chemin d'accès à l'élément en question. Pour ce faire, utilisez la méthode resolve() bien nommée. Pour résoudre le problème, élément peut être un enfant direct ou indirect du répertoire.

// Resolve the path of the previously created file called "My Notes.txt".
const path = await newDirectoryHandle.resolve(newFileHandle);
// `path` is now ["My Documents", "My Notes.txt"]

Supprimer des fichiers et des dossiers dans un répertoire

Si vous avez obtenu l'accès à un répertoire, vous pouvez supprimer les fichiers et dossiers qu'il contient à l'aide de la commande removeEntry(). Pour les dossiers, la suppression peut être récursive et inclure tous les sous-dossiers et les fichiers qu'ils contiennent.

// Delete a file.
await directoryHandle.removeEntry('Abandoned Projects.txt');
// Recursively delete a folder.
await directoryHandle.removeEntry('Old Stuff', { recursive: true });

Supprimer directement un fichier ou un dossier

Si vous avez accès à un handle de fichier ou de répertoire, appelez remove() sur un FileSystemFileHandle ou FileSystemDirectoryHandle pour la supprimer.

// Delete a file.
await fileHandle.remove();
// Delete a directory.
await directoryHandle.remove();

Renommer et déplacer des fichiers et des dossiers

Les fichiers et les dossiers peuvent être renommés ou déplacés vers un nouvel emplacement en appelant move() au niveau de la FileSystemHandle. FileSystemHandle comporte les interfaces enfants FileSystemFileHandle et FileSystemDirectoryHandle La méthode move() accepte un ou deux paramètres. La première peut être être une chaîne avec le nouveau nom ou un FileSystemDirectoryHandle vers le dossier de destination. Dans le second paramètre facultatif est une chaîne portant le nouveau nom. Le déplacement et le changement de nom peuvent donc s’effectuent en une seule étape.

// Rename the file.
await file.move('new_name');
// Move the file to a new directory.
await file.move(directory);
// Move the file to a new directory and rename it.
await file.move(directory, 'newer_name');

Intégration par glisser-déposer

La Interfaces HTML de type glisser-déposer permettre aux applications Web d'accepter fichiers glissés-déposés sur une page Web. Lors d'une opération de glisser-déposer, les éléments des fichiers et répertoires déplacés sont associés avec respectivement des entrées de fichier et des entrées de répertoire. DataTransferItem.getAsFileSystemHandle() renvoie une promesse avec un objet FileSystemFileHandle si l'élément déplacé est un fichier et qu'une promet avec un objet FileSystemDirectoryHandle si l'élément déplacé est un répertoire. La liste suivante le montre en action. Notez que l'interface utilisateur de la fonction Glisser-déposer DataTransferItem.kind correspond à "file" pour les fichiers et les répertoires, tandis que FileSystemHandle.kind de l'API File System Access est "file" pour les fichiers et "directory" pour les répertoires.

elem.addEventListener('dragover', (e) => {
  // Prevent navigation.
  e.preventDefault();
});

elem.addEventListener('drop', async (e) => {
  e.preventDefault();

  const fileHandlesPromises = [...e.dataTransfer.items]
    .filter((item) => item.kind === 'file')
    .map((item) => item.getAsFileSystemHandle());

  for await (const handle of fileHandlesPromises) {
    if (handle.kind === 'directory') {
      console.log(`Directory: ${handle.name}`);
    } else {
      console.log(`File: ${handle.name}`);
    }
  }
});

Accéder au système de fichiers privé d'origine

Le système de fichiers privé d'origine est un point de terminaison de stockage qui, comme son nom l'indique, est privé l'origine de la page. Bien que les navigateurs implémentent généralement cette fonctionnalité en persistant système de fichiers privé d'origine vers le disque quelque part sur le disque, il n'est pas destiné à ce que le contenu soit accessibles. De même, les fichiers ou répertoires dont le nom correspond à la liste des répertoires noms des enfants du système de fichiers privé d’origine existent. Bien que le navigateur puisse donner l’impression que de fichiers internes (puisqu'il s'agit d'un système de fichiers d'origine privé), le navigateur peut les stocker ces "fichiers" dans une base de données ou toute autre structure de données. En gros, si vous utilisez cette API, ne vous attendez pas à trouver les fichiers créés qui correspondent à un fichier spécifique quelque part sur le disque dur. Vous pouvez opérer comme d'habitude sur le système de fichiers privé d'origine une fois que vous avez accès à la racine FileSystemDirectoryHandle.

const root = await navigator.storage.getDirectory();
// Create a new file handle.
const fileHandle = await root.getFileHandle('Untitled.txt', { create: true });
// Create a new directory handle.
const dirHandle = await root.getDirectoryHandle('New Folder', { create: true });
// Recursively remove a directory.
await root.removeEntry('Old Stuff', { recursive: true });

Navigateurs pris en charge

  • Chrome: 86 <ph type="x-smartling-placeholder">
  • Edge: 86 <ph type="x-smartling-placeholder">
  • Firefox: 111 <ph type="x-smartling-placeholder">
  • Safari: 15.2. <ph type="x-smartling-placeholder">

Source

Accéder aux fichiers optimisés pour les performances à partir du système de fichiers privé d'origine

Le système de fichiers d'origine fournit un accès facultatif à un type particulier de fichier optimisé pour les performances, par exemple en offrant un accès en écriture sur place et exclusif à l'accès contenus. Dans Chromium 102 et les versions ultérieures, il existe une méthode supplémentaire sur le système de fichiers privé d'origine pour simplifiant l'accès aux fichiers: createSyncAccessHandle() (pour les opérations de lecture et d'écriture synchrones). Il est exposé sur FileSystemFileHandle, mais exclusivement dans Nœuds de calcul Web

// (Read and write operations are synchronous,
// but obtaining the handle is asynchronous.)
// Synchronous access exclusively in Worker contexts.
const accessHandle = await fileHandle.createSyncAccessHandle();
const writtenBytes = accessHandle.write(buffer);
const readBytes = accessHandle.read(buffer, { at: 1 });

Polyremplissage

Il n'est pas possible de polyfill complètement les méthodes de l'API File System Access.

  • La méthode showOpenFilePicker() peut être approximative avec un élément <input type="file">.
  • La méthode showSaveFilePicker() peut être simulée avec un élément <a download="file_name">. mais cela déclenche un téléchargement programmatique et ne permet pas d'écraser des fichiers existants.
  • La méthode showDirectoryPicker() peut être émulée avec l'API non standard Élément <input type="file" webkitdirectory>.

Nous avons développé une bibliothèque appelée browser-fs-access qui utilise l'API l'API System Access autant que possible, et qui s'appuie sur ces meilleures options dans toutes les autres cas d'utilisation.

Sécurité et autorisations

L'équipe Chrome a conçu et mis en œuvre l'API File System Access selon les principes fondamentaux définies dans la section Contrôler l'accès à des fonctionnalités puissantes de plate-forme Web, y compris les règles le contrôle et la transparence, et l'ergonomie.

Ouvrir un fichier ou enregistrer un nouveau fichier

<ph type="x-smartling-placeholder">
</ph> Sélecteur de fichier pour ouvrir un fichier à lire <ph type="x-smartling-placeholder">
</ph> Sélecteur de fichier utilisé pour ouvrir un fichier existant afin de le lire.

Lors de l'ouverture d'un fichier, l'utilisateur accorde l'autorisation de lire un fichier ou un répertoire à l'aide du sélecteur de fichier. Le sélecteur de fichier ouvert ne peut s'afficher qu'à l'aide d'un geste de l'utilisateur lorsqu'il est diffusé depuis une interface sécurisée le contexte. Si les utilisateurs changent d'avis, ils peuvent annuler la sélection dans le fichier. et le site n'a accès à rien. Ce comportement est identique à celui de la Élément <input type="file">.

<ph type="x-smartling-placeholder">
</ph> Sélecteur de fichier pour enregistrer un fichier sur le disque. <ph type="x-smartling-placeholder">
</ph> Un sélecteur de fichier utilisé pour enregistrer un fichier sur le disque.

De même, lorsqu'une application Web souhaite enregistrer un nouveau fichier, le navigateur affiche le sélecteur d'enregistrement de fichier, permettant à l'utilisateur de spécifier le nom et l'emplacement du nouveau fichier. Puisqu'il enregistre un nouveau fichier à l'appareil (au lieu d'écraser un fichier existant), le sélecteur de fichier autorise l'application à écrire dans le fichier.

Dossiers restreints

Pour protéger les utilisateurs et leurs données, le navigateur peut limiter la capacité de l'utilisateur à enregistrer dans certaines tels que les dossiers du système d'exploitation comme Windows ou les dossiers de la bibliothèque macOS. Dans ce cas, le navigateur affiche une invite et demande à l'utilisateur de choisir une autre .

Modifier un fichier ou un répertoire existant

Une application Web ne peut pas modifier un fichier sur un disque sans obtenir l'autorisation explicite de l'utilisateur.

Invite concernant l'autorisation

Si une personne souhaite enregistrer les modifications apportées à un fichier auquel elle a précédemment accordé un accès en lecture, le navigateur affiche une invite d’autorisation, demandant l’autorisation pour le site d’écrire des modifications sur le disque. La demande d'autorisation ne peut être déclenchée que par un geste de l'utilisateur (par exemple, en cliquant sur un bouton .

<ph type="x-smartling-placeholder">
</ph> Une invite d&#39;autorisation s&#39;affiche avant l&#39;enregistrement d&#39;un fichier. <ph type="x-smartling-placeholder">
</ph> Invite présentée aux utilisateurs avant que le navigateur ne soit autorisé à écrire sur un fichier existant.

Une appli Web qui modifie plusieurs fichiers, comme un IDE, peut aussi demander l'autorisation d'enregistrer les changements au moment de l’ouverture.

Si l'utilisateur choisit "Annuler" et n'accorde pas l'accès en écriture, l'application Web ne peut pas enregistrer les modifications fichier local. Elle doit fournir à l'utilisateur une autre méthode pour enregistrer ses données, par par exemple en permettant de "télécharger" le fichier ou l'enregistrement de données dans le cloud.

Transparence

<ph type="x-smartling-placeholder">
</ph> Icône de l&#39;omnibox <ph type="x-smartling-placeholder">
</ph> Icône de la barre d'adresse indiquant que l'utilisateur a autorisé le site Web à enregistrer dans un fichier local.

Une fois qu'un utilisateur a autorisé une application Web à enregistrer un fichier local, le navigateur affiche une icône dans la barre d'adresse. En cliquant sur l'icône, un pop-up s'ouvre et affiche la liste des fichiers fournis par l'utilisateur. y accéder. L'utilisateur peut toujours révoquer cet accès s'il le souhaite.

Persistance des autorisations

L'application Web peut continuer à enregistrer les modifications apportées au fichier sans afficher d'invite jusqu'à ce que tous les onglets de son sont fermées. Lorsqu'un onglet est fermé, le site perd tout accès. La prochaine fois que l'utilisateur utilisera l'application Web, il sera de nouveau invité à accéder aux fichiers.

Commentaires

Nous aimerions connaître votre avis sur votre expérience avec l'API File System Access.

Présentez-nous la conception de l'API

Y a-t-il un aspect de l'API qui ne fonctionne pas comme prévu ? Ou manque-t-il des méthodes ou les propriétés dont vous avez besoin pour mettre en œuvre votre idée ? Vous avez une question ou un commentaire sur la sécurité ?

Vous rencontrez un problème lors de l'implémentation ?

Avez-vous détecté un bug dans l'implémentation de Chrome ? Ou l'implémentation est-elle différente des spécifications ?

  • Signalez un bug sur https://new.crbug.com. Veillez à inclure autant de détails que possible, les instructions de reproduction et définissez Components sur Blink>Storage>FileSystem. Glitch est idéal pour partager des répétitions rapides.

Vous prévoyez d'utiliser l'API ?

Vous prévoyez d'utiliser l'API File System Access sur votre site ? Votre soutien public nous aide à prioriser et montre aux autres fournisseurs de navigateurs à quel point il est essentiel de les prendre en charge.

Liens utiles

Remerciements

La spécification de l'API File System Access a été écrite par Marijn Kruisselbrink