跳转到内容

Origin Private File System(OPFS,源私有文件系统)

发布于

一句话: 根据 MDN,“origin private file system(OPFS,源私有文件系统)是 File System API 提供的一个存储端点,它私有于页面所在的源,且不像常规文件系统那样对用户可见”,并提供“对其内容的 原地写入访问”。

MDN 总结了 OPFS 与 File System Access API 所操作的用户可见文件之间的若干区别:OPFS “与其他任何 按源分区的存储机制(例如 IndexedDB API)一样,受浏览器存储配额限制”;可以通过 navigator.storage.estimate() 查看其用量;“清除站点的存储数据会删除 OPFS”;“访问 OPFS 中的文件 不需要权限提示或安全检查”;以及“OPFS 并非设计为对用户可见”。MDN 还指出 OPFS 提供“低层级、逐字节 的文件访问”,并且由于跳过了用户可见 File System Access API 所需的选择器/权限安全检查,“因而速度 更快”。

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

MDN 指出:“要首先访问 OPFS,需要调用 navigator.storage.getDirectory() 方法。该方法返回一个 FileSystemDirectoryHandle 对象的引用,代表 OPFS 的根目录。” 在主线程中,文件与目录通过异步、 基于 Promise 的 FileSystemDirectoryHandle.getFileHandle() 与 getDirectoryHandle() 访问,传入 { create: true } “会在文件或文件夹不存在时创建它”。

在专用 Worker(dedicated Web Worker)中同步访问

Section titled “在专用 Worker(dedicated Web Worker)中同步访问”

MDN 解释道,OPFS “还提供了一组同步调用(File System API 的其他调用均为异步)“以提升性能,并且 所返回的 FileSystemSyncAccessHandle “仅能在专用 Worker(dedicated Web Worker)内访问”,从而使 其同步方法不会阻塞主线程执行。尽管名称中带有 “Sync”,MDN 指出”createSyncAccessHandle() 方法 本身是异步的”:

// 在专用 Worker(dedicated Web Worker)内
const opfsRoot = await navigator.storage.getDirectory();
const fileHandle = await opfsRoot.getFileHandle("fast", { create: true });
const accessHandle = await fileHandle.createSyncAccessHandle();
const content = new TextEncoder().encode("Some text");
accessHandle.write(content, { at: 0 });
accessHandle.flush();
accessHandle.close();

MDN 列出了返回的 FileSystemSyncAccessHandle 上的同步方法:getSize()(“返回文件的字节大小”)、 write()(“将缓冲区内容写入文件,可选择在给定偏移处写入,并返回已写入的字节数”)、read() (“将文件内容读取到缓冲区,可选择从给定偏移处读取”)、truncate()(“将文件大小调整为给定 大小”)、flush()(“确保文件内容包含通过 write() 完成的所有修改”)、以及 close() (“关闭该访问句柄”)。

async function openOpfsFile(name) {
if (!("storage" in navigator) || !("getDirectory" in navigator.storage)) {
// 此处不支持 OPFS——改用 IndexedDB 或内存中存储作为回退方案。
return null;
}
const opfsRoot = await navigator.storage.getDirectory();
return opfsRoot.getFileHandle(name, { create: true });
}

MDN 将 OPFS 标记为 Baseline:广泛可用,指出“自 2023 年 3 月起,它已在各浏览器中可用”。MDN 还将其标注为安全上下文特性(“仅在安全上下文(HTTPS)中可用,视支持的浏览器而定”)。同步的 FileSystemSyncAccessHandle 方法则根据 MDN,“仅能在专用 Worker(dedicated Web Worker)内访问”。

  • 使用前先做 navigator.storage?.getDirectory 特性检测,即便 MDN 将 OPFS 标记为自 2023 年 3 月起 Baseline 广泛可用——较旧或非浏览器环境可能仍不具备它。
  • 通过 HTTPS 提供页面;MDN 将 OPFS 记录为仅限安全上下文的特性。
  • 仅在专用 Worker(dedicated Web Worker)内使用同步的 FileSystemSyncAccessHandle 方法 (read()、write()、flush()、close())——MDN 指出该类“仅能在专用 Worker(dedicated Web Worker)内访问”,以避免阻塞主线程。共享 Worker(shared worker)与 Service Worker 不受支持。
  • 记住 createSyncAccessHandle() 本身返回一个 Promise,尽管其名称中带有 “Sync”(根据 MDN)。
  • 不要指望 OPFS 中的内容对用户可见,也不要指望它能在“清除存储数据”操作后存活——MDN 指出 清除站点存储会删除 OPFS,且它“并非设计为对用户可见”。
  • 为浏览器存储配额限制预留余量,因为 MDN 指出 OPFS “与其他任何按源分区的存储机制一样,受 浏览器存储配额限制”。