Interfejs File System Access API: upraszcza dostęp do plików lokalnych

Interfejs File System Access API umożliwia aplikacjom internetowym odczytywanie i zapisywanie zmian bezpośrednio w plikach i folderach na urządzeniu użytkownika.

Czym jest interfejs File System Access API?

Interfejs File System Access API umożliwia programistom tworzenie zaawansowanych aplikacji internetowych, które współpracują z pliki na lokalnym urządzeniu użytkownika, takie jak IDE, edytory zdjęć i filmów czy edytory tekstu. Po użytkownik udziela aplikacji internetowej dostępu, ten interfejs API umożliwia odczyt lub zapisywanie zmian bezpośrednio w plikach foldery na urządzeniu użytkownika. Oprócz odczytu i zapisu plików interfejs File System Access API zapewnia otwieranie katalogu i wyliczenie jego zawartości.

Jeśli masz już doświadczenie w czytaniu i pisaniu plików, pokażę Ci, znanych Ci filmów. Mimo to zachęcam do jej przeczytania, ponieważ nie wszystkie systemy są takie same.

Interfejs File System Access API jest obsługiwany przez większość przeglądarek Chromium Windows, macOS, ChromeOS i Linux. Istotnym wyjątkiem jest Brave, obecnie dostępne tylko za flagą. Pracujemy nad obsługą Androida w kontekście strony crbug.com/1011535.

Używanie interfejsu File System Access API

Aby przedstawić możliwości i przydatność interfejsu File System Access API, napisałem jeden tekst w jednym pliku . Za jego pomocą można otworzyć plik tekstowy, edytować go, zapisać zmiany z powrotem na dysku oraz rozpocząć utwórz nowy plik i zapisz zmiany na dysku. To nic niezwykłego, ale zawiera wystarczająco dużo, aby pomóc Ci rozumieją pojęcia.

Obsługa przeglądarek

Obsługa przeglądarek

  • Chrome: 86.
  • Edge: 86.
  • Firefox: funkcja nieobsługiwana.
  • Safari: nieobsługiwane.

Źródło

Wykrywanie cech

Aby dowiedzieć się, czy interfejs File System Access API jest obsługiwany, sprawdź, czy metoda selektora który Cię interesuje.

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

Wypróbuj

Zobacz, jak działa interfejs File System Access API w edytora tekstu.

Odczytywanie pliku z lokalnego systemu plików

W pierwszym przykładzie chcę przedstawić użytkownikom prośbę o wybranie pliku, a następnie go otworzyć i przeczytać. z dysku.

Poproś użytkownika o wskazanie pliku do przeczytania

Punkt wejścia interfejsu File System Access API to window.showOpenFilePicker() Po wywołaniu wyświetla się okno wyboru plików, i prosi o wybranie pliku. Po wybraniu pliku interfejs API zwraca tablicę pliku. uchwytów. Opcjonalny parametr options pozwala wpływać na działanie selektora plików, np. Na przykład pozwalając użytkownikowi wybrać wiele plików, katalogów lub różnych typów plików. Jeśli nie określisz żadnych opcji, selektor plików umożliwi użytkownikowi wybranie pojedynczego pliku. To jest doskonale sprawdza się w edytorze tekstu.

Podobnie jak wiele innych zaawansowanych interfejsów API, showOpenFilePicker() trzeba wywoływać w bezpiecznym miejscu kontekst i musi być wywoływana gestem użytkownika.

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

Gdy użytkownik wybierze plik, showOpenFilePicker() zwraca tablicę nicków, w tym przypadku jednoelementowej tablicy z jednym FileSystemFileHandle, który zawiera właściwości oraz i metod interakcji z plikiem.

Warto zachować odwołanie do uchwytu pliku, aby móc go użyć później. Będzie potrzebne do zapisania zmian w pliku lub wykonania innych operacji na pliku.

Odczytywanie pliku z systemu plików

Teraz, gdy masz już nick dla pliku, możesz pobrać jego właściwości lub uzyskać dostęp do samego pliku. Na razie przeczytam tylko jego treść. Połączenie z numerem handle.getFile() zwraca File który zawiera obiekt blob. Aby pobrać dane z obiektu blob, wywołaj jeden z jego , (slice(), stream(), text() lub arrayBuffer()).

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

Obiekt File zwrócony przez funkcję FileSystemFileHandle.getFile() jest czytelny tylko tak długo, jak długo bazowy plik na dysku nie uległ zmianie. Jeśli plik na dysku zostanie zmodyfikowany, obiekt File stanie się nie można odczytać i trzeba wywołać ponownie getFile(), aby uzyskać nowy obiekt File w celu odczytania zmienionych i skalowalnych danych.

Podsumowanie

Gdy użytkownik kliknie przycisk Otwórz, w przeglądarce pojawi się selektor plików. Gdy wybierzą plik, aplikacja odczytuje treści i umieszcza je w elemencie <textarea>.

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

Zapisz plik w lokalnym systemie plików

W edytorze tekstu możesz zapisać plik na dwa sposoby: Zapisz lub Zapisz jako. Zapisz zapisuje zmiany z powrotem w oryginalnym pliku przy użyciu pobranego wcześniej uchwytu pliku. Ale zaoszczędź As tworzy nowy plik i dlatego wymaga nowego uchwytu.

Utwórz nowy plik

Aby zapisać plik, wywołaj showSaveFilePicker(). Wyświetli się selektor plików. w „zapisz” w którym użytkownik może wybrać nowy plik, którego chce użyć do zapisania. Dla tekstu Chciałem też, by automatycznie dodawało rozszerzenie .txt, więc dodałem .

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

Zapisz zmiany na dysku

Cały kod do zapisywania zmian w pliku znajdziesz w mojej prezentacji edytora tekstu na stronie GitHub Podstawowe interakcje systemu plików są fs-helpers.js Najprościej wygląda to tak, jak pokazano poniżej. Omówię każdy krok i wyjaśnię go.

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

Do zapisywania danych na dysku wykorzystywany jest obiekt FileSystemWritableFileStream, podklasa z WritableStream. Utwórz strumień, wywołując w pliku funkcję createWritable() i „obsługiwany obiekt”. Po wywołaniu funkcji createWritable() przeglądarka najpierw sprawdza, czy użytkownik udzielił zgody uprawnienia do zapisu w pliku. Jeśli uprawnienia do zapisu nie zostały przyznane, przeglądarka wyświetli komunikat użytkownik musi uzyskać odpowiednie uprawnienia. Jeśli uprawnienia nie są przyznane, createWritable() wysyła zapytanie DOMException, a aplikacja nie będzie mogła zapisać w tym pliku. W edytorze tekstu Obiekty DOMException są obsługiwane w metodzie saveFile().

Metoda write() pobiera ciąg znaków, który jest niezbędny w edytorze tekstu. Może to też zająć BufferSource lub Blob. Możesz na przykład użyć potoku, aby przesłać strumień bezpośrednio do :

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

Możesz też seek() lub truncate() w strumieniu, aby zaktualizować w określonym miejscu lub zmień jego rozmiar.

Określanie sugerowanej nazwy pliku i katalogu początkowego

W wielu przypadkach może być konieczne, aby aplikacja sugerowała domyślną nazwę pliku lub domyślną lokalizację. Na przykład tekst Edytor może zaproponować domyślną nazwę pliku Untitled Text.txt zamiast Untitled. Ty można to osiągnąć, przekazując właściwość suggestedName w opcjach showSaveFilePicker.

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

To samo dotyczy domyślnego katalogu początkowego. Jeśli tworzysz edytor tekstu, otwierać okno zapisywania lub otwierania pliku w domyślnym folderze documents, natomiast w przypadku obrazu w edytorze pictures. Możesz zaproponować domyślny początek przez przekazanie właściwości startIn do funkcji showSaveFilePicker, showDirectoryPicker() lub showOpenFilePicker podobnych metod.

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

Oto lista dobrze znanych katalogów systemowych:

  • desktop: katalog na komputerze użytkownika, jeśli istnieje taki element.
  • documents: katalog, w którym zwykle przechowywane są dokumenty utworzone przez użytkownika.
  • downloads: katalog, w którym zwykle są przechowywane pobrane pliki.
  • music: katalog, w którym zwykle są przechowywane pliki audio.
  • pictures: katalog, w którym zwykle są przechowywane zdjęcia i inne obrazy.
  • videos: katalog, w którym zwykle są przechowywane materiały wideo.

Poza dobrze znanymi katalogami systemowymi można również przekazać istniejący uchwyt pliku lub katalogu jako wartość w kolumnie startIn. Okno zostanie otwarte w tym samym katalogu.

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

Określanie przeznaczenia różnych selektorów plików

Czasami aplikacje mają różne selektory do różnych celów. Na przykład tekst sformatowany umożliwia otwieranie plików tekstowych i importowanie obrazów. Domyślnie każdy plik spowoduje otwarcie go w ostatniej zapamiętanej lokalizacji. Możesz to obejść, przechowując wartości id dla każdego typu selektora. Jeśli jest określony atrybut id, implementacja selektora plików zapamiętuje oddzielnym ostatnim używanym katalogu dla tego zasobu (id).

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

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

Przechowywanie uchwytów plików lub uchwytów katalogów w IndexedDB

Uchwyty plików i uchwyty katalogów są serializowalne, co oznacza, że możesz zapisać plik lub uchwyt katalogu do IndexedDB lub wywołanie postMessage(), aby przesłać je między tym samym najwyższym poziomem pochodzeniu danych.

Zapisywanie uchwytów plików lub katalogu w IndexedDB oznacza, że możesz zapisywać stan plików lub katalogów, nad którymi pracował użytkownik. Dzięki temu możesz zachować listę lub edytowanych plików, zaproponować ponowne otwarcie ostatniego pliku po otwarciu aplikacji, przywrócenie poprzedniego pliku katalogu usług i nie tylko. W edytorze tekstu przechowuję listę 5 ostatnich plików użytkownika co pozwoliło uzyskać do nich dostęp.

Poniższy przykładowy kod pokazuje przechowywanie i pobieranie uchwytu pliku oraz uchwytu katalogu. Dostępne opcje zobacz, jak to działa w Glitch. (Używam dla zachowania zwięzłości biblioteki idb-keyval).

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

Uchwyty i uprawnienia przechowywanego pliku lub katalogu

Uprawnienia nie zawsze są zachowywane między sesjami, więc sprawdź, czy użytkownik przyznał(a) uprawnienia do pliku lub katalogu za pomocą: queryPermission(). Jeśli nie, zadzwoń requestPermission(), aby (ponownie) poprosić o nie. To samo działa w przypadku uchwytów plików i katalogów. Ty muszą uruchomić fileOrDirectoryHandle.requestPermission(descriptor) lub fileOrDirectoryHandle.queryPermission(descriptor).

W edytorze tekstu utworzyłem metodę verifyPermission(), która sprawdza, czy użytkownik użytkownik wyraził zgodę i w razie potrzeby przesyła żądanie.

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

Poprzez przesłanie prośby o uprawnienia do zapisu udało mi się zmniejszyć liczbę próśb o uprawnienia. użytkownik widzi jeden prompt przy otwarciu pliku i przyznaje uprawnienia zarówno do odczytu, jak i do zapisu.

Otwieranie katalogu i wyliczanie jego zawartości

Aby wyliczyć wszystkie pliki w katalogu, wywołaj showDirectoryPicker(). Użytkownik wybiera katalog w selektorze, po którym następuje znak FileSystemDirectoryHandle , co umożliwia wyliczanie plików katalogu i uzyskiwanie do nich dostępu. Domyślnie odczytywane są dostęp do plików w katalogu, ale jeśli potrzebujesz uprawnień do zapisu, możesz { mode: 'readwrite' } do metody.

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

Jeśli musisz dodatkowo uzyskać dostęp do każdego pliku przy użyciu usługi getFile(), na przykład po to, aby uzyskać indywidualną rozmiarów plików, nie używaj opcji await w każdym wyniku po kolei, zamiast tego przetwarzać wszystkie pliki równoległe, na przykład za pomocą funkcji 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));
});

tworzenie plików i folderów w katalogu oraz uzyskiwanie do nich dostępu;

W katalogu możesz tworzyć pliki i foldery albo uzyskiwać do nich dostęp za pomocą getFileHandle() lub odpowiednio getDirectoryHandle() . Przekazując opcjonalny obiekt options z kluczem create i wartością logiczną true lub false, możesz określić, czy należy utworzyć nowy plik lub folder, jeśli nie istnieje.

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

Rozpoznawanie ścieżki elementu w katalogu

Podczas pracy z plikami lub folderami w katalogu może być pomocne rozwiązanie ścieżki do elementu w związku z naruszeniem naszych przepisów. Użyj w tym celu metody o błędnej nazwie resolve(). Aby rozwiązać ten problem, Element może być bezpośrednim lub pośrednim podrzędnym katalogiem.

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

Usuwanie plików i folderów z katalogu

Jeśli masz dostęp do katalogu, możesz usunąć zawarte w nim pliki i foldery za pomocą removeEntry(). W przypadku folderów usuwanie może być opcjonalnie rekurencyjne i obejmować wszystkich podfolderów i znajdujących się w nich plików.

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

Bezpośrednie usuwanie pliku lub folderu

Jeśli masz dostęp do pliku lub uchwytu katalogu, wywołaj remove() w FileSystemFileHandle lub FileSystemDirectoryHandle, aby go usunąć.

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

Zmienianie nazw i przenoszenie plików oraz folderów

Pliki i foldery można przenieść do nowej lokalizacji lub zmienić ich nazwę, wywołując funkcję move() na interfejsu FileSystemHandle. FileSystemHandle ma interfejsy podrzędne FileSystemFileHandle i FileSystemDirectoryHandle Metoda move() przyjmuje 1 lub 2 parametry. Pierwszy z nich może być ciągiem z nową nazwą lub ciągiem FileSystemDirectoryHandle do folderu docelowego. W W drugim przypadku opcjonalny drugi parametr jest ciągiem z nową nazwą, więc jego przeniesienie i zmiana nazwy wystarczy wykonać jeden krok.

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

Integracja metodą „przeciągnij i upuść”

Interfejs HTML metodą „przeciągnij i upuść” włącz akceptowanie aplikacji internetowych przeciągnięte i upuszczone pliki na stronie internetowej. Podczas przeciągania i upuszczania przeciągane elementy pliku i katalogu są powiązane z wpisami odpowiednio plików i katalogu. DataTransferItem.getAsFileSystemHandle() zwraca obietnicę z obiektem FileSystemFileHandle, jeśli przeciągnięty element jest plikiem, a z obiektem FileSystemDirectoryHandle, jeśli przeciągnięty element jest katalogiem. Następująca strona pokazuje to w praktyce. Pamiętaj, że funkcja „Przeciągnij i upuść” DataTransferItem.kind to "file" w przypadku plików i katalogów, natomiast FileSystemHandle.kind interfejsu File System Access API jest "file" na pliki i "directory" na katalogi.

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

Uzyskiwanie dostępu do prywatnego systemu plików punktu początkowego

Prywatny system plików punktu początkowego to punkt końcowy pamięci masowej, który, jak sama nazwa wskazuje, jest prywatny pochodzenie strony. Przeglądarki zazwyczaj implementują to, zachowując zawartość pierwotny system plików na dysk, nie jest to przeznaczone dla użytkownika i łatwo dostępnych rozwiązań. Nie należy również oczekiwać, że pliki lub katalogi o nazwach pasujących do zapytania nazwy elementów podrzędnych początkowego systemu plików istnieją. Chociaż przeglądarka może sprawiać takie wrażenie, są pliki, które są używane wewnętrznie – jest to prywatny system plików punktu początkowego – przeglądarka może zapisywać te „pliki” w bazie danych lub innej strukturze danych. Zasadniczo, jeśli używasz tego interfejsu API, nie spodziewaj się, że utworzone pliki będą w innym miejscu na dysku twardym i identyczne. W tych dniach: do prywatnego systemu plików punktu początkowego, gdy będziesz mieć dostęp do katalogu głównego 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 });

Obsługa przeglądarek

  • Chrome: 86.
  • Edge: 86.
  • Firefox: 111.
  • Safari: 15.2

Źródło

Uzyskiwanie dostępu do plików zoptymalizowanych pod kątem wydajności z prywatnego systemu plików punktu początkowego

Prywatny system plików punktu początkowego zapewnia opcjonalny dostęp do specjalnego rodzaju pliku, który zapewnia optymalizację pod kątem wydajności, na przykład przez oferowanie lokalnego i wyłącznego dostępu do treści. W Chromium 102 i nowszych wersjach dostępna jest dodatkowa metoda w prywatnym systemie plików źródła, dla której upraszczanie dostępu do plików: createSyncAccessHandle() (na potrzeby synchroniczne operacje odczytu i zapisu). Ekspozycja zostanie udostępniona FileSystemFileHandle, ale wyłącznie w Skrypty internetowe.

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

Polyfill

Nie można w pełni wypełnić metod interfejsu File System Access API.

  • Metodę showOpenFilePicker() można określić w przybliżeniu za pomocą elementu <input type="file">.
  • Metodę showSaveFilePicker() można symulować za pomocą elementu <a download="file_name">, ale uruchamia to pobieranie programowe i nie pozwala na zastępowanie istniejących plików.
  • Metoda showDirectoryPicker() może być nieco emulowana za pomocą metody niestandardowej <input type="file" webkitdirectory>.

Opracowaliśmy bibliotekę o nazwie browser-fs-access, która wykorzystuje Interfejs System Access API wszędzie tam, gdzie jest to możliwe i który nawiązuje do tych najlepszych najlepszych opcji przypadków.

Bezpieczeństwo i uprawnienia

Zespół Chrome zaprojektował i wdrożył interfejs File System Access API, kierując się podstawowymi zasadami w artykule Kontrola nad dostępem do zaawansowanych funkcji platform internetowych, w tym kontrolę i przejrzystość oraz ergonomię użytkownika.

Otwieranie pliku lub zapisywanie nowego

Okno wyboru plików umożliwiające otwarcie pliku do odczytu
Selektor plików służący do otwierania istniejącego pliku w celu odczytu.

Po otwarciu pliku użytkownik przyznaje uprawnienia do odczytu pliku lub katalogu za pomocą selektora plików. Otwarty selektor plików można wyświetlić gestem użytkownika tylko wtedy, gdy jest on wyświetlany z bezpiecznej kontekstu. Jeśli użytkownik zmieni zdanie, może anulować zaznaczenie w pliku. , a witryna nie uzyska dostępu do żadnych elementów. Działa to tak samo jak w przypadku <input type="file"> element.

Selektor plików umożliwiający zapisanie pliku na dysku.
Selektor plików służący do zapisywania pliku na dysku.

Podobnie, gdy aplikacja internetowa chce zapisać nowy plik, przeglądarka wyświetla selektor plików, co umożliwia użytkownikowi określenie nazwy i lokalizacji nowego pliku. Zapisują nowy plik (w przeciwieństwie do zastępowania istniejącego pliku) selektor plików przyznaje aplikacji uprawnienia i zapisać dane w pliku.

Foldery z ograniczonym dostępem

Aby chronić użytkowników i ich dane, przeglądarka może ograniczyć użytkownikowi możliwość zapisywania w niektórych na przykład podstawowe foldery systemu operacyjnego, takie jak Windows, czy foldery biblioteki macOS. W takim przypadku przeglądarka wyświetla pytanie i prosi użytkownika o wybranie innej wartości. folderu Dysku.

Modyfikowanie istniejącego pliku lub katalogu

Aplikacja internetowa nie może modyfikować pliku na dysku bez uzyskania wyraźnej zgody użytkownika.

Prośba o zgodę

Jeśli ktoś chce zapisać zmiany w pliku, któremu wcześniej przyznała uprawnienia do odczytu, przeglądarka wyświetla monit o przyznanie uprawnień z prośbą o zgodę na zapisywanie zmian na dysku. Prośba o uprawnienia może być aktywowana tylko gestem użytkownika, na przykład przez kliknięcie przycisku Zapisz Przycisk

Prośba o zgodę jest wyświetlana przed zapisaniem pliku.
Monit wyświetlany użytkownikom, zanim przeglądarka otrzyma uprawnienia do zapisu dostęp do istniejącego pliku.

Aplikacja internetowa, która edytuje wiele plików, np. IDE, może też poprosić o uprawnienia do zapisu. zmienia się w chwili otwarcia.

Jeśli użytkownik wybierze Anuluj i nie przyzna uprawnień do zapisu, aplikacja internetowa nie będzie mogła zapisać zmian w pliku lokalnym. Powinien on zapewniać użytkownikowi alternatywną metodę zapisywania danych, na przykład: na przykład przez udostępnienie sposobu „pobierania” plik lub zapisanie danych w chmurze.

Przejrzystość

Ikona omniboksu
Ikona na pasku adresu wskazująca, że użytkownik przyznał witrynie uprawnienia do i zapisać w pliku lokalnym.

Gdy użytkownik zezwoli aplikacji internetowej na zapisywanie pliku lokalnego, w przeglądarce pojawi się ikona na pasku adresu. Kliknięcie ikony otwiera wyskakujące okienko z listą plików przekazanych przez użytkownika . Użytkownik może w każdej chwili cofnąć dostęp.

Trwałość uprawnień

Aplikacja internetowa może dalej zapisywać zmiany w pliku bez pytania, dopóki wszystkie karty punkty początkowe są zamknięte. Po zamknięciu karty witryna utraci do niej pełny dostęp. Gdy następnym razem użytkownik użyje aplikacji internetowej, zostanie ponownie wyświetlona prośba o dostęp do plików.

Prześlij opinię

Chętnie poznamy Twoją opinię na temat interfejsu File System Access API.

Opowiedz nam o konstrukcji interfejsu API

Czy jest coś, co nie działa w interfejsie API zgodnie z oczekiwaniami? Czy może brakuje tu metod lub właściwości potrzebne do realizacji pomysłu? Masz pytanie lub komentarz na temat zabezpieczeń model?

Problem z implementacją?

Czy wystąpił błąd z implementacją Chrome? Czy implementacja różni się od specyfikacji?

  • Zgłoś błąd na https://new.crbug.com. Podaj jak najwięcej szczegółów. instrukcji odtwarzania i ustaw opcję Komponenty na Blink>Storage>FileSystem. Błąd świetnie nadaje się do udostępniania szybkich poprawek.

Planujesz korzystać z interfejsu API?

Planujesz użyć w swojej witrynie interfejsu File System Access API? Twoje publiczne wsparcie pomaga nam potraktować priorytetowo i pokazuje innym dostawcom przeglądarek, jak ważne jest ich zapewnienie.

Przydatne linki

Podziękowania

Specyfikacja interfejsu File System Access API została napisana przez Marijn Kruisselbrink