Spec-Zone.ru › Web APIs

Система частных файлов происхождения

Безопасный контекст: Эта функция доступна только в безопасных контекстах (HTTPS), в некоторых или всех поддерживающих браузерах.

Примечание: Эта функция доступна в Потоках Web Workers.

Система частных файлов происхождения (OPFS) — это конечная точка хранения, предоставляемая в рамках API файловой системы, которая является частной для происхождения страницы и не отображается пользователю, как обычная файловая система. Она предоставляет доступ к специальному виду файлов, высоко оптимизированному для производительности, и обеспечивает доступ к содержимому файла в месте его записи.

Работа с файлами с помощью API доступа к файловой системе

API доступа к файловой системе, который расширяет API файловой системы, предоставляет доступ к файлам с помощью методов выбора файлов. Например:

  1. Window.showOpenFilePicker() позволяет пользователю выбрать файл для доступа, что приводит к возврату объекта FileSystemFileHandle.
  2. FileSystemFileHandle.getFile() вызывается для получения доступа к содержимому файла, содержимое изменяется с помощью FileSystemFileHandle.createWritable() / FileSystemWritableFileStream.write().
  3. FileSystemHandle.requestPermission({mode: 'readwrite'}) используется для запроса разрешения пользователя на сохранение изменений.
  4. Если пользователь принимает запрос на разрешение, изменения сохраняются обратно в исходный файл.

Это работает, но имеет некоторые ограничения. Эти изменения вносятся в видимую пользователю файловую систему, поэтому в ней существует множество проверок безопасности (например, безопасный просмотр в Chrome), которые предотвращают запись вредоносного контента в эту файловую систему. Эти записи выполняются не непосредственно, а с использованием временного файла. Исходный файл не изменяется, пока не пройдёт проверку всех проверок безопасности.

В результате эти операции довольно медленные. Это не так заметно при небольших изменениях текста, но производительность страдает при более значительных, масштабных обновлениях файлов, таких как изменения баз данных SQLite.

Как OPFS решает такие проблемы?

OPFS предлагает доступ к файлам на низком уровне, байт за байтом, который является частным для происхождения страницы и не виден пользователю. В результате он не требует той же серии проверок безопасности и предоставления разрешений, и поэтому быстрее, чем вызовы API доступа к файловой системе. Он также имеет набор синхронных вызовов (другие вызовы API файловой системы асинхронны), которые могут выполняться только внутри потоков Web Workers, чтобы не блокировать главный поток.

В качестве резюме, как OPFS отличается от видимой пользователем файловой системы:

  • OPFS подчиняется ограничениям квот браузера на хранение, как и любой другой механизм хранения, разделенный по происхождению (например, API IndexedDB). Вы можете получить доступ к объёму дискового пространства, используемого OPFS, с помощью navigator.storage.estimate().
  • Очистка данных хранилища для сайта удаляет OPFS.
  • Для доступа к файлам в OPFS не требуются запросы разрешения и проверки безопасности.
  • Браузеры сохраняют содержимое OPFS на диске в каком-то месте, но вы не можете ожидать, что созданные файлы будут соответствовать друг другу один к одному. OPFS не предназначен для отображения пользователю.

Как получить доступ к OPFS?

Чтобы получить доступ к OPFS, вызывается метод navigator.storage.getDirectory(). Он возвращает ссылку на объект FileSystemDirectoryHandle, который представляет корень OPFS.

Работа с OPFS из основного потока

При доступе к OPFS из основного потока используются асинхронные API, основанные на Promise. Доступ к файлам (FileSystemFileHandle) и каталогам (FileSystemDirectoryHandle) осуществляется с помощью вызовов FileSystemDirectoryHandle.getFileHandle() и FileSystemDirectoryHandle.getDirectoryHandle() соответственно на объекте FileSystemDirectoryHandle, представляющем корень OPFS (и дочерние каталоги, при их создании).

Примечание: Передача { create: true } в вышеуказанные методы приводит к созданию файла или папки, если они не существуют.

// Create a hierarchy of files and folders
const fileHandle = await opfsRoot.getFileHandle("my first file", {
  create: true,
});
const directoryHandle = await opfsRoot.getDirectoryHandle("my first folder", {
  create: true,
});
const nestedFileHandle = await directoryHandle.getFileHandle(
  "my first nested file",
  { create: true },
);
const nestedDirectoryHandle = await directoryHandle.getDirectoryHandle(
  "my first nested folder",
  { create: true },
);

// Access existing files and folders via their names
const existingFileHandle = await opfsRoot.getFileHandle("my first file");
const existingDirectoryHandle =
  await opfsRoot.getDirectoryHandle("my first folder");

Чтение файла

  1. Вызовите FileSystemDirectoryHandle.getFileHandle() для возврата объекта FileSystemFileHandle.
  2. Вызовите метод FileSystemFileHandle.getFile() для возврата объекта File. Это специализированный тип Blob, и, как таковой, с ним можно работать так же, как и с любым другим Blob. Например, вы можете получить прямой доступ к текстовому содержимому с помощью Blob.text().

Запись файла

  1. Вызовите FileSystemDirectoryHandle.getFileHandle() для возврата объекта FileSystemFileHandle.
  2. Вызовите FileSystemFileHandle.createWritable() для возврата объекта FileSystemWritableFileStream, который является специализированным типом WritableStream.
  3. Запишите содержимое в него с помощью вызова FileSystemWritableFileStream.write().
  4. Закройте поток с помощью WritableStream.close().

Удаление файла или папки

Вы можете вызвать FileSystemDirectoryHandle.removeEntry() на родительском каталоге, передав ему имя элемента, который нужно удалить:

directoryHandle.removeEntry("my first nested file");

Также можно вызвать FileSystemHandle.remove() на объектах FileSystemFileHandle или FileSystemDirectoryHandle, представляющих элемент, который нужно удалить. Для удаления папки, включая все подпапки, передайте опцию { recursive: true }.

await fileHandle.remove();
await directoryHandle.remove({ recursive: true });

Следующее предоставляет быстрый способ очистить весь OPFS:

await (await navigator.storage.getDirectory()).remove({ recursive: true });

Перечисление содержимого папки

FileSystemDirectoryHandle является асинхронным итератором. Как таковой, вы можете перебирать его с помощью цикла for await...of и стандартных методов, таких как entries(), values() и keys().

Например:

for await (let [name, handle] of directoryHandle) {
}
for await (let [name, handle] of directoryHandle.entries()) {
}
for await (let handle of directoryHandle.values()) {
}
for await (let name of directoryHandle.keys()) {
}

Работа с OPFS из потока Web Worker

Потоки Web Workers не блокируют главный поток, что означает, что в этом контексте вы можете использовать синхронные API доступа к файлам. Синхронные API быстрее, так как они не требуют работы с обещаниями.

Вы можете синхронно получить доступ к файлу, вызвав FileSystemFileHandle.createSyncAccessHandle() на обычном объекте FileSystemFileHandle:

Примечание: Несмотря на наличие «Sync» в названии, сам метод createSyncAccessHandle() является асинхронным.

const opfsRoot = await navigator.storage.getDirectory();
const fileHandle = await opfsRoot.getFileHandle("my-high-speed-file.txt", {
  create: true,
});
const syncAccessHandle = await fileHandle.createSyncAccessHandle();

На возвращенном объекте FileSystemSyncAccessHandle доступно несколько синхронных методов:

  • getSize(): Возвращает размер файла в байтах.
  • write(): Записывает содержимое буфера в файл, необязательно по заданному смещению, и возвращает количество записанных байтов. Проверка возвращенного количества записанных байтов позволяет вызывающим сторонам обнаруживать и обрабатывать ошибки и частичные записи.
  • read(): Считывает содержимое файла в буфер, необязательно по заданному смещению.
  • truncate(): Изменяет размер файла на заданный размер.
  • flush(): Убеждается, что содержимое файла содержит все изменения, внесенные с помощью write().
  • close(): Закрывает обработчик доступа.

Вот пример, использующий все упомянутые выше методы:

const opfsRoot = await navigator.storage.getDirectory();
const fileHandle = await opfsRoot.getFileHandle("fast", { create: true });
const accessHandle = await fileHandle.createSyncAccessHandle();

const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();

// Initialize this variable for the size of the file.
let size;
// The current size of the file, initially `0`.
size = accessHandle.getSize();
// Encode content to write to the file.
const content = textEncoder.encode("Some text");
// Write the content at the beginning of the file.
accessHandle.write(content, { at: size });
// Flush the changes.
accessHandle.flush();
// The current size of the file, now `9` (the length of "Some text").
size = accessHandle.getSize();

// Encode more content to write to the file.
const moreContent = textEncoder.encode("More content");
// Write the content at the end of the file.
accessHandle.write(moreContent, { at: size });
// Flush the changes.
accessHandle.flush();
// The current size of the file, now `21` (the length of
// "Some textMore content").
size = accessHandle.getSize();

// Prepare a data view of the length of the file.
const dataView = new DataView(new ArrayBuffer(size));

// Read the entire file into the data view.
accessHandle.read(dataView, { at: 0 });
// Logs `"Some textMore content"`.
console.log(textDecoder.decode(dataView));

// Read starting at offset 9 into the data view.
accessHandle.read(dataView, { at: 9 });
// Logs `"More content"`.
console.log(textDecoder.decode(dataView));

// Truncate the file after 4 bytes.
accessHandle.truncate(4);

См. также

  • Система частных файлов происхождения на web.dev

© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API