De File System Access API: vereenvoudigt de toegang tot lokale bestanden

Met de File System Access API kunnen webapps rechtstreeks wijzigingen in bestanden en mappen op het apparaat van de gebruiker lezen en opslaan.

Wat is de File System Access API?

Met de File System Access API kunnen ontwikkelaars krachtige webapps bouwen die communiceren met bestanden op het lokale apparaat van de gebruiker, zoals IDE's, foto- en video-editors, teksteditors en meer. Nadat een gebruiker een webapp toegang heeft verleend, kan deze API bestanden en mappen op het apparaat van de gebruiker rechtstreeks lezen en er wijzigingen in opslaan. Naast het lezen en schrijven van bestanden biedt de File System Access API de mogelijkheid om een ​​directory te openen en de inhoud ervan te inventariseren.

Als je al eerder met het lezen en schrijven van bestanden hebt gewerkt, zal veel van wat ik ga delen je bekend voorkomen. Ik raad je aan om het toch te lezen, want niet alle systemen zijn hetzelfde.

De File System Access API wordt ondersteund door de meeste Chromium-browsers op Windows, macOS, ChromeOS, Linux en Android. Een opvallende uitzondering is Brave, waar deze momenteel alleen beschikbaar is achter een vlag .

De API voor bestandssysteemtoegang gebruiken

Om de kracht en bruikbaarheid van de File System Access API te demonstreren, heb ik een teksteditor voor één bestand geschreven. Hiermee kun je een tekstbestand openen, bewerken, de wijzigingen opslaan op schijf, of een nieuw bestand starten en de wijzigingen opslaan op schijf. Het is niets bijzonders, maar biedt voldoende om je de concepten te helpen begrijpen.

Browserondersteuning

Browser Support

  • Chroom: 86.
  • Rand: 86.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Source

Functiedetectie

Om erachter te komen of de File System Access API wordt ondersteund, controleert u of de pickermethode waarin u geïnteresseerd bent, bestaat.

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

Probeer het eens

Bekijk de File System Access API in actie in de demo van de teksteditor .

Een bestand lezen van het lokale bestandssysteem

Het eerste gebruiksvoorbeeld dat ik wil aanpakken, is de gebruiker vragen om een ​​bestand te selecteren, dat bestand vervolgens te openen en vanaf de schijf te lezen.

Vraag de gebruiker om een ​​bestand te kiezen om te lezen

Het toegangspunt tot de File System Access API is window.showOpenFilePicker() . Wanneer deze wordt aangeroepen, wordt een dialoogvenster voor het selecteren van bestanden geopend en wordt de gebruiker gevraagd een bestand te selecteren. Nadat een bestand is geselecteerd, retourneert de API een reeks bestandshandles. Met een optionele parameter options ' kunt u het gedrag van de bestandskiezer beïnvloeden, bijvoorbeeld door de gebruiker toe te staan ​​meerdere bestanden, mappen of verschillende bestandstypen te selecteren. Zonder opgegeven opties kan de bestandskiezer één bestand selecteren. Dit is perfect voor een teksteditor.

Net als bij veel andere krachtige API's moet het aanroepen van showOpenFilePicker() in een beveiligde context gebeuren en moet dit vanuit een gebruikersgebaar gebeuren.

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

Zodra de gebruiker een bestand selecteert, retourneert showOpenFilePicker() een array met handles. In dit geval een array met één element en één FileSystemFileHandle die de eigenschappen en methoden bevat die nodig zijn om met het bestand te communiceren.

Het is handig om een ​​verwijzing naar de bestandsnaam te bewaren, zodat deze later gebruikt kan worden. Deze is nodig om wijzigingen in het bestand op te slaan of andere bestandsbewerkingen uit te voeren.

Een bestand lezen van het bestandssysteem

Nu je een handle naar een bestand hebt, kun je de eigenschappen van het bestand ophalen of het bestand zelf benaderen. Voor nu lees ik de inhoud ervan. Het aanroepen van handle.getFile() retourneert een File object, dat een blob bevat. Om de gegevens uit de blob op te halen, roep je een van de methoden aan ( slice() , stream() , text() arrayBuffer() ).

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

Het File object dat door FileSystemFileHandle.getFile() wordt geretourneerd, is alleen leesbaar zolang het onderliggende bestand op schijf niet is gewijzigd. Als het bestand op schijf wordt gewijzigd, wordt het File object onleesbaar en moet u getFile() opnieuw aanroepen om een ​​nieuw File object te verkrijgen dat de gewijzigde gegevens kan lezen.

Alles bij elkaar optellen

Wanneer gebruikers op de knop Openen klikken, toont de browser een bestandskiezer. Zodra ze een bestand hebben geselecteerd, leest de app de inhoud en plaatst deze in een <textarea> .

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

Schrijf het bestand naar het lokale bestandssysteem

In de teksteditor zijn er twee manieren om een ​​bestand op te slaan: Opslaan en Opslaan als . Opslaan schrijft de wijzigingen terug naar het oorspronkelijke bestand met behulp van de eerder opgehaalde bestandshandle. Opslaan als maakt echter een nieuw bestand aan en vereist dus een nieuwe bestandshandle.

Een nieuw bestand maken

Om een ​​bestand op te slaan, roept u showSaveFilePicker() aan. De bestandskiezer wordt dan in de "opslaan"-modus weergegeven, zodat de gebruiker een nieuw bestand kan kiezen om op te slaan. Voor de teksteditor wilde ik ook automatisch een .txt extensie toevoegen, dus gaf ik een aantal extra parameters op.

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

Wijzigingen opslaan op schijf

Je vindt alle code voor het opslaan van wijzigingen in een bestand in mijn demo van de teksteditor op GitHub . De belangrijkste interacties met het bestandssysteem staan ​​in fs-helpers.js . In zijn eenvoudigste vorm ziet het proces eruit als de volgende code. Ik zal elke stap doorlopen en uitleggen.

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

Het schrijven van gegevens naar schijf maakt gebruik van een FileSystemWritableFileStream -object, een subklasse van WritableStream . Creëer de stream door createWritable() aan te roepen op het bestandshandle-object. Wanneer createWritable() wordt aangeroepen, controleert de browser eerst of de gebruiker schrijfrechten voor het bestand heeft. Als deze rechten niet zijn verleend, vraagt ​​de browser de gebruiker om toestemming. Als deze rechten niet zijn verleend, genereert createWritable() een DOMException en kan de app niet naar het bestand schrijven. In de teksteditor worden de DOMException objecten verwerkt in de saveFile() -methode.

De write() -methode accepteert een string, wat nodig is voor een teksteditor. Maar hij kan ook een BufferSource of een Blob accepteren. Je kunt er bijvoorbeeld een stream rechtstreeks naartoe leiden:

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.
}

U kunt ook seek() of truncate() binnen de stream uitvoeren om het bestand op een specifieke positie bij te werken of de bestandsgrootte te wijzigen.

Een voorgestelde bestandsnaam en startmap opgeven

In veel gevallen wilt u dat uw app een standaardbestandsnaam of -locatie voorstelt. Een teksteditor kan bijvoorbeeld de standaardbestandsnaam Untitled Text.txt voorstellen in plaats van Untitled . U kunt dit bereiken door de eigenschap suggestedName door te geven als onderdeel van de showSaveFilePicker -opties.

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

Hetzelfde geldt voor de standaard startmap. Als u een teksteditor bouwt, kunt u het dialoogvenster 'Bestand opslaan' of 'Bestand openen' het beste starten in de documents , terwijl u voor een afbeeldingseditor de pictures kunt gebruiken. U kunt een standaard startmap voorstellen door een eigenschap startIn door te geven aan de methoden showSaveFilePicker , showDirectoryPicker() of showOpenFilePicker , zoals hier.

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

De lijst met bekende systeemmappen is:

  • desktop : De bureaubladmap van de gebruiker, indien deze bestaat.
  • documents : Map waarin doorgaans door de gebruiker gemaakte documenten worden opgeslagen.
  • downloads : map waarin gedownloade bestanden doorgaans worden opgeslagen.
  • music : Map waar doorgaans audiobestanden worden opgeslagen.
  • pictures : Map waar doorgaans foto's en andere stilstaande beelden worden opgeslagen.
  • videos : map waarin doorgaans video's of films worden opgeslagen.

Naast bekende systeemmappen kunt u ook een bestaande bestands- of map-handle als waarde voor startIn opgeven. Het dialoogvenster wordt dan in dezelfde map geopend.

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

Het doel van verschillende bestandskiezers specificeren

Soms hebben applicaties verschillende kiezers voor verschillende doeleinden. Een RTF-editor kan de gebruiker bijvoorbeeld toestaan ​​om tekstbestanden te openen, maar ook om afbeeldingen te importeren. Standaard wordt elke bestandskiezer geopend op de laatst onthouden locatie. U kunt dit omzeilen door id waarden voor elk type kiezer op te slaan. Als een id is opgegeven, onthoudt de implementatie van de bestandskiezer een aparte laatst gebruikte directory voor die id .

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

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

Bestands- of directory-handles opslaan in IndexedDB

Bestands- en directory-handles zijn serialiseerbaar, wat betekent dat u een bestands- of directory-handle kunt opslaan in IndexedDB, of postMessage() kunt aanroepen om ze tussen dezelfde hoofdbron te verzenden.

Het opslaan van bestands- of directory-handles in IndexedDB betekent dat je de status kunt opslaan of kunt onthouden aan welke bestanden of directory's een gebruiker werkte. Dit maakt het mogelijk om een ​​lijst bij te houden van recent geopende of bewerkte bestanden, aan te bieden om het laatste bestand opnieuw te openen wanneer de app wordt geopend, de vorige werkdirectory te herstellen, en meer. In de teksteditor sla ik een lijst op van de vijf meest recente bestanden die de gebruiker heeft geopend, zodat deze bestanden opnieuw toegankelijk zijn.

Het volgende codevoorbeeld toont het opslaan en ophalen van een bestands- en directory-handle. Je kunt dit in actie zien op Glitch. (Ik gebruik de idb-keyval- bibliotheek voor de beknoptheid.)

import { get, set } from 'https://unpkg.com/[email protected]/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);
  }
});

Opgeslagen bestands- of directory-handles en machtigingen

Omdat machtigingen niet altijd tussen sessies behouden blijven , moet u controleren of de gebruiker machtigingen voor het bestand of de map heeft verleend met behulp van queryPermission() . Zo niet, roep dan requestPermission() aan om deze (opnieuw) aan te vragen. Dit werkt hetzelfde voor bestands- en maphandles. U moet respectievelijk fileOrDirectoryHandle.requestPermission(descriptor) of fileOrDirectoryHandle.queryPermission(descriptor) uitvoeren.

In de teksteditor heb ik een verifyPermission() methode gemaakt die controleert of de gebruiker al toestemming heeft verleend en, indien nodig, de aanvraag indient.

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

Door schrijfrechten aan te vragen bij de leesaanvraag, kon ik het aantal toestemmingvragen beperken. Bij het openen van het bestand ziet de gebruiker één vraag en verleent toestemming om zowel te lezen als te schrijven.

Een directory openen en de inhoud ervan opsommen

Om alle bestanden in een directory te inventariseren, roept u showDirectoryPicker() aan. De gebruiker selecteert een directory in een selector, waarna een FileSystemDirectoryHandle wordt geretourneerd, waarmee u de bestanden in de directory kunt inventariseren en openen. Standaard heeft u leestoegang tot de bestanden in de directory, maar als u schrijftoegang nodig hebt, kunt u { mode: 'readwrite' } aan de methode doorgeven.

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

Als u daarnaast ook nog eens toegang tot elk bestand nodig hebt met behulp van getFile() om bijvoorbeeld de individuele bestandsgroottes op te vragen, moet u niet opeenvolgend await op elk resultaat, maar alle bestanden parallel verwerken, bijvoorbeeld met behulp van 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));
});

Bestanden en mappen in een directory maken of openen

Vanuit een directory kunt u bestanden en mappen aanmaken of openen met behulp van de methode getFileHandle() of getDirectoryHandle() . Door een optioneel options met de sleutel create en de booleaanse waarde true of false door te geven, kunt u bepalen of er een nieuw bestand of een nieuwe map moet worden aangemaakt als deze nog niet bestaat.

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

Het pad van een item in een directory oplossen

Bij het werken met bestanden of mappen in een directory kan het handig zijn om het pad van het betreffende item te achterhalen. Dit kan met de toepasselijk genaamde methode resolve() . Voor het achterhalen van de oorzaak kan het item een ​​direct of indirect onderliggend item van de directory zijn.

// 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"]

Bestanden en mappen in een map verwijderen

Als u toegang hebt verkregen tot een directory, kunt u de bestanden en mappen erin verwijderen met de removeEntry() methode. Voor mappen kan het verwijderen optioneel recursief zijn en alle submappen en de daarin aanwezige bestanden omvatten.

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

Een bestand of map rechtstreeks verwijderen

Als u toegang hebt tot een bestands- of directory-handle, roept u remove() aan op een FileSystemFileHandle of FileSystemDirectoryHandle om deze te verwijderen.

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

Bestanden en mappen hernoemen en verplaatsen

Bestanden en mappen kunnen worden hernoemd of verplaatst naar een nieuwe locatie door move() aan te roepen op de FileSystemHandle interface. FileSystemHandle heeft de onderliggende interfaces FileSystemFileHandle en FileSystemDirectoryHandle . De move() methode accepteert één of twee parameters. De eerste kan een string met de nieuwe naam zijn of een FileSystemDirectoryHandle naar de doelmap. In het laatste geval is de optionele tweede parameter een string met de nieuwe naam, zodat verplaatsen en hernoemen in één stap kan gebeuren.

// 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');

Integratie met slepen en neerzetten

De HTML Drag and Drop-interfaces stellen webapplicaties in staat om gesleepte en neergezette bestanden op een webpagina te accepteren. Tijdens een drag and drop-bewerking worden gesleepte bestands- en directory-items respectievelijk gekoppeld aan bestandsitems en directory-items. De DataTransferItem.getAsFileSystemHandle() -methode retourneert een promise met een FileSystemFileHandle -object als het gesleepte item een ​​bestand is, en een promise met een FileSystemDirectoryHandle -object als het gesleepte item een ​​directory is. De volgende tabel laat dit in de praktijk zien. Merk op dat de DataTransferItem.kind van de Drag and Drop-interface "file" is voor zowel bestanden als directory's, terwijl FileSystemHandle.kind van de File System Access API "file" is voor bestanden en "directory" voor directory's.

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

Toegang krijgen tot het oorspronkelijke privébestandssysteem

Het private bestandssysteem van de oorsprong is een opslageindpunt dat, zoals de naam al doet vermoeden, privé is ten opzichte van de oorsprong van de pagina. Hoewel browsers dit doorgaans implementeren door de inhoud van dit private bestandssysteem ergens op schijf op te slaan, is het niet de bedoeling dat de inhoud toegankelijk is voor de gebruiker. Evenmin wordt verwacht dat er bestanden of mappen bestaan ​​met namen die overeenkomen met de namen van onderliggende bestanden van het private bestandssysteem van de oorsprong. Hoewel de browser het misschien doet lijken alsof er bestanden zijn, kan de browser deze "bestanden" intern opslaan in een database of een andere datastructuur – aangezien dit een private bestandssysteem van de oorsprong is. Kortom, als u deze API gebruikt, verwacht dan niet dat de aangemaakte bestanden ergens op de harde schijf één-op-één overeenkomen. U kunt zoals gebruikelijk werken op het private bestandssysteem van de oorsprong zodra u toegang hebt tot de root 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 });

Browser Support

  • Chroom: 86.
  • Rand: 86.
  • Firefox: 111.
  • Safari: 15.2.

Source

Toegang tot bestanden die zijn geoptimaliseerd voor prestaties vanuit het oorspronkelijke privébestandssysteem

Het oorspronkelijke private bestandssysteem biedt optionele toegang tot een speciaal type bestand dat sterk geoptimaliseerd is voor prestaties, bijvoorbeeld door in-place en exclusieve schrijftoegang tot de inhoud van een bestand te bieden. In Chromium 102 en hoger is er een extra methode op het oorspronkelijke private bestandssysteem om de toegang tot bestanden te vereenvoudigen: createSyncAccessHandle() (voor synchrone lees- en schrijfbewerkingen). Deze methode is beschikbaar op FileSystemFileHandle , maar uitsluitend in Web Workers .

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

Polyfilling

Het is niet mogelijk om de File System Access API-methoden volledig te polyvullen.

  • De showOpenFilePicker() methode kan worden benaderd met een <input type="file"> element.
  • De methode showSaveFilePicker() kan worden gesimuleerd met een <a download="file_name"> -element. Dit activeert echter een programmatische download en staat niet toe dat bestaande bestanden worden overschreven.
  • De showDirectoryPicker() methode kan enigszins worden nagebootst met het niet-standaardelement <input type="file" webkitdirectory> .

We hebben een bibliotheek ontwikkeld met de naam browser-fs-access die waar mogelijk gebruikmaakt van de File System Access API en in alle andere gevallen terugvalt op deze op één na beste opties.

Beveiliging en machtigingen

Het Chrome-team heeft de File System Access API ontworpen en geïmplementeerd op basis van de kernprincipes die zijn gedefinieerd in Controlling Access to Powerful Web Platform Features , waaronder gebruikerscontrole en transparantie en gebruikersergonomie.

Een bestand openen of een nieuw bestand opslaan

Bestandskiezer om een ​​bestand te openen om te lezen
Een bestandskiezer waarmee u een bestaand bestand kunt openen om te lezen.

Bij het openen van een bestand geeft de gebruiker toestemming om een ​​bestand of map te lezen met behulp van de bestandskiezer. De bestandskiezer kan alleen worden weergegeven met een gebruikersgebaar wanneer deze wordt bediend vanuit een beveiligde context . Als gebruikers van gedachten veranderen, kunnen ze de selectie in de bestandskiezer annuleren en krijgt de site geen toegang meer. Dit is hetzelfde gedrag als dat van het element <input type="file"> .

Bestandskiezer om een ​​bestand op schijf op te slaan.
Een bestandskiezer waarmee u een bestand op schijf kunt opslaan.

Op dezelfde manier toont de browser de bestandskiezer wanneer een webapp een nieuw bestand wil opslaan. Hiermee kan de gebruiker de naam en locatie van het nieuwe bestand opgeven. Omdat er een nieuw bestand op het apparaat wordt opgeslagen (in plaats van een bestaand bestand te overschrijven), geeft de bestandskiezer de app toestemming om naar het bestand te schrijven.

Beperkte mappen

Om gebruikers en hun gegevens te beschermen, kan de browser de mogelijkheid van de gebruiker om in bepaalde mappen op te slaan beperken, bijvoorbeeld mappen van het kernbesturingssysteem zoals Windows of de bibliotheekmappen van macOS. Wanneer dit gebeurt, toont de browser een prompt en vraagt ​​de gebruiker om een ​​andere map te kiezen.

Een bestaand bestand of map wijzigen

Een webapplicatie kan een bestand op schijf niet wijzigen zonder expliciete toestemming van de gebruiker.

Toestemmingsprompt

Als iemand wijzigingen wil opslaan in een bestand waarvoor hij/zij eerder leestoegang heeft verleend, toont de browser een toestemmingsverzoek waarin toestemming wordt gevraagd aan de site om wijzigingen naar schijf te schrijven. Het toestemmingsverzoek kan alleen worden geactiveerd door een gebruikersgebaar, bijvoorbeeld door op de knop Opslaan te klikken.

Er wordt toestemming gevraagd voordat een bestand wordt opgeslagen.
Vraag aan gebruikers voordat de browser schrijfrechten krijgt voor een bestaand bestand.

Een webapplicatie die meerdere bestanden bewerkt, zoals een IDE, kan ook bij het openen om toestemming vragen om de wijzigingen op te slaan.

Als de gebruiker Annuleren kiest en geen schrijftoegang verleent, kan de webapp geen wijzigingen in het lokale bestand opslaan. De webapp moet de gebruiker een alternatieve methode bieden om zijn gegevens op te slaan, bijvoorbeeld door het bestand te 'downloaden' of door gegevens in de cloud op te slaan.

Transparantie

Omnibox-pictogram
Adresbalkpictogram dat aangeeft dat de gebruiker de website toestemming heeft gegeven om in een lokaal bestand op te slaan.

Zodra een gebruiker toestemming heeft gegeven aan een webapp om een ​​lokaal bestand op te slaan, toont de browser een pictogram in de adresbalk. Door op het pictogram te klikken, wordt een pop-up geopend met een lijst met bestanden waartoe de gebruiker toegang heeft gegeven. De gebruiker kan die toegang altijd weer intrekken.

Permissiepersistentie

De webapp kan wijzigingen in het bestand blijven opslaan zonder dat u hierom wordt gevraagd totdat alle tabbladen van de bron zijn gesloten. Zodra een tabblad is gesloten, verliest de site alle toegang. De volgende keer dat de gebruiker de webapp gebruikt, wordt hij of zij opnieuw gevraagd om toegang tot de bestanden.

Feedback

Wij willen graag uw ervaringen met de File System Access API horen.

Vertel ons over het API-ontwerp

Werkt er iets aan de API dat niet werkt zoals u had verwacht? Of ontbreken er methoden of eigenschappen die u nodig hebt om uw idee te implementeren? Heeft u een vraag of opmerking over het beveiligingsmodel?

Probleem met de implementatie?

Heb je een bug gevonden in de implementatie van Chrome? Of wijkt de implementatie af van de specificatie?

Wilt u de API gebruiken?

Bent u van plan de File System Access API op uw site te gebruiken? Uw publieke steun helpt ons om functies te prioriteren en laat andere browserleveranciers zien hoe belangrijk het is om deze te ondersteunen.

Nuttige links

Dankbetuigingen

De File System Access API-specificatie is geschreven door Marijn Kruisselbrink .