FileSystemFileHandle:createSyncAccessHandle() 方法

基线 2023

新可用

2023 年 3 月起,此功能可在最新的设备和浏览器版本中使用。此功能可能在较旧的设备或浏览器中无法使用。

安全上下文:此功能仅在安全上下文(HTTPS)中可用,在某些或所有支持的浏览器中可用。

注意:此功能仅在专用 Web 工作线程中可用。

createSyncAccessHandle() 方法是 FileSystemFileHandle 接口的方法,它返回一个 Promise,该 Promise 解析为一个 FileSystemSyncAccessHandle 对象,该对象可用于同步读取和写入文件。此方法的同步特性带来了性能优势,但它仅可在专用Web 工作线程中用于来源私有文件系统中的文件。

创建 FileSystemSyncAccessHandle 会对与文件句柄关联的文件进行独占锁定。这将阻止创建其他 FileSystemSyncAccessHandleFileSystemWritableFileStream,直到现有的访问句柄关闭。

语法

js
createSyncAccessHandle()
createSyncAccessHandle(options)

参数

options 可选

具有以下属性的对象

mode 可选 非标准

指定访问句柄锁定模式的字符串。默认值为 "readwrite"。可能的值为

"read-only"

可以在一个文件上同时打开多个 FileSystemSyncAccessHandle 对象(例如,在多个选项卡中使用同一个应用程序时),前提是它们都以 "read-only" 模式打开。打开后,可以在句柄上调用类似读取的方法——read()getSize()close()

"readwrite"

只能在一个文件上打开一个 FileSystemSyncAccessHandle 对象。在第一个句柄关闭之前尝试打开后续句柄会导致抛出 NoModificationAllowedError 异常。打开后,可以在句柄上调用任何可用的方法。

"readwrite-unsafe"

可以在一个文件上同时打开多个 FileSystemSyncAccessHandle 对象,前提是它们都以 "readwrite-unsafe" 模式打开。打开后,可以在句柄上调用任何可用的方法。

返回值

一个 Promise,它解析为一个 FileSystemSyncAccessHandle 对象。

异常

NotAllowedError DOMException

如果句柄的 PermissionStatus.statereadwrite 模式下不是 granted,则抛出此异常。

InvalidStateError DOMException

如果 FileSystemSyncAccessHandle 对象不代表 来源私有文件系统中的文件,则抛出此异常。

NotFoundError DOMException

如果找不到当前条目,则抛出此异常。

NoModificationAllowedError DOMException

如果浏览器无法获取与文件句柄关联的文件的锁定,则抛出此异常。这可能是因为 mode 设置为 readwrite,并且尝试同时打开多个句柄。

示例

基本用法

以下异步事件处理程序函数包含在 Web 工作线程中。其中的代码段创建了一个同步文件访问句柄。

js
onmessage = async (e) => {
  // Retrieve message sent to work from main script
  const message = e.data;

  // Get handle to draft file
  const root = await navigator.storage.getDirectory();
  const draftHandle = await root.getFileHandle("draft.txt", { create: true });
  // Get sync access handle
  const accessHandle = await draftHandle.createSyncAccessHandle();

  // …

  // Always close FileSystemSyncAccessHandle if done.
  accessHandle.close();
};

包含 mode 选项的完整示例

我们的createSyncAccessHandle() 模式测试示例提供了一个<input>字段用于输入文本,以及两个按钮——一个用于将输入的文本写入来源私有文件系统中的文件末尾,另一个用于在文件变得太满时清空文件。

尝试探索上面的演示,并打开浏览器开发者控制台,以便您可以看到发生了什么。如果您尝试在多个浏览器选项卡中打开演示,您会发现可以同时打开多个句柄以同时写入文件。这是因为在 createSyncAccessHandle() 调用上设置了 mode: "readwrite-unsafe"

下面我们将探讨代码。

HTML

两个<button>元素和文本<input>字段如下所示

html
<ol>
  <li>
    <label for="filetext">Enter text to write to the file:</label>
    <input type="text" id="filetext" name="filetext" />
  </li>
  <li>
    Write your text to the file: <button class="write">Write text</button>
  </li>
  <li>
    Empty the file if it gets too full:
    <button class="empty">Empty file</button>
  </li>
</ol>

主要 JavaScript

HTML 文件中的主线程 JavaScript 如下所示。我们获取对写入文本按钮、清空文件按钮和文本输入字段的引用,然后使用 Worker() 构造函数创建一个新的 Web 工作线程。然后,我们定义两个函数并将它们设置为按钮上的事件处理程序

  • 单击写入文本按钮时运行 writeToOPFS()。此函数使用 Worker.postMessage() 方法将文本字段的输入值发布到工作线程中的一个对象中,然后清空文本字段,准备进行下一次添加。请注意,传递的对象还包含一个 command: "write" 属性,以指定我们希望使用此消息触发写入操作。
  • 单击清空文件按钮时运行 emptyOPFS()。这会将包含 command: "empty" 属性的对象发布到工作线程,指定要清空文件。
js
const writeBtn = document.querySelector(".write");
const emptyBtn = document.querySelector(".empty");
const fileText = document.querySelector("#filetext");

const opfsWorker = new Worker("worker.js");

function writeToOPFS() {
  opfsWorker.postMessage({
    command: "write",
    content: fileText.value,
  });
  console.log("Main script: Text posted to worker");
  fileText.value = "";
}

function emptyOPFS() {
  opfsWorker.postMessage({
    command: "empty",
  });
}

writeBtn.addEventListener("click", writeToOPFS);
emptyBtn.addEventListener("click", emptyOPFS);

工作线程 JavaScript

工作线程 JavaScript 如下所示。

首先,我们运行一个名为 initOPFS() 的函数,该函数使用 StorageManager.getDirectory() 获取对 OPFS 根目录的引用,使用 FileSystemDirectoryHandle.getFileHandle() 创建一个文件并返回其句柄,然后使用 createSyncAccessHandle() 返回一个 FileSystemSyncAccessHandle。此调用包含 mode: "readwrite-unsafe" 属性,允许多个句柄同时访问同一文件。

js
let accessHandle;

async function initOPFS() {
  const opfsRoot = await navigator.storage.getDirectory();
  const fileHandle = await opfsRoot.getFileHandle("file.txt", { create: true });
  accessHandle = await fileHandle.createSyncAccessHandle({
    mode: "readwrite-unsafe",
  });
}

initOPFS();

在工作线程的 消息事件处理程序函数中,我们首先使用 getSize() 获取文件的大小。然后,我们检查消息中发送的数据是否包含 command 属性值为 "empty"。如果是,我们使用 truncate() 和值为 0 来清空文件,并更新 size 变量中包含的文件大小。

如果消息数据是其他内容,我们将

  • 创建一个新的 TextEncoderTextDecoder 以便稍后处理文本内容的编码和解码。
  • 编码消息数据并将结果写入文件的末尾,使用 write(),然后更新 size 变量中包含的文件大小。
  • 创建一个 DataView 来包含文件内容,并使用 read() 将内容读取到其中。
  • 解码 DataView 内容并将其记录到控制台。
js
onmessage = function (e) {
  console.log("Worker: Message received from main script");

  // Get the current size of the file
  let size = accessHandle.getSize();

  if (e.data.command === "empty") {
    // Truncate the file to 0 bytes
    accessHandle.truncate(0);

    // Get the current size of the file
    size = accessHandle.getSize();
  } else {
    const textEncoder = new TextEncoder();
    const textDecoder = new TextDecoder();

    // Encode content to write to the file
    const content = textEncoder.encode(e.data.content);
    // Write the content at the end of the file
    accessHandle.write(content, { at: size });

    // Get the current size of the file
    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 });

    // Log the current file contents to the console
    console.log("File contents: " + textDecoder.decode(dataView));

    // Flush the changes
    accessHandle.flush();
  }

  // Log the size of the file to the console
  console.log("Size: " + size);
};

规范

规范
文件系统标准
# api-filesystemfilehandle-createsyncaccesshandle

浏览器兼容性

BCD 表仅在启用 JavaScript 的浏览器中加载。

另请参阅