FileSystemFileHandle: createSyncAccessHandle() 方法

Baseline 已廣泛支援

此功能已成熟,並可在許多裝置和瀏覽器版本上執行。自 2023 年 3 月以來,它已在各種瀏覽器中可用。

安全上下文: 此功能僅在安全上下文(HTTPS)中可用,且支援此功能的瀏覽器數量有限。

注意:此功能僅在 專用 Web Worker 中可用。

FileSystemFileHandle 介面的 createSyncAccessHandle() 方法返回一個 Promise,該 Promise 解析為一個 FileSystemSyncAccessHandle 物件,可用於同步地讀取和寫入檔案。此方法的同步性帶來了效能優勢,但它只能在專用 Web Worker 中用於 源私有檔案系統 內的檔案。

建立 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 Worker 中。其中的程式碼片段會建立一個同步檔案訪問控制代碼。

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="file-text">Enter text to write to the file:</label>
    <input type="text" id="file-text" name="file-text" />
  </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 Worker。然後,我們定義兩個函式並將它們設定為按鈕的事件處理程式。

  • 當點選寫入文字按鈕時,會執行 writeToOPFS()。此函式使用 Worker.postMessage() 方法將文字欄位的輸入值作為物件傳送到 Worker,然後清空文字欄位,為下一次新增做好準備。請注意,傳遞的物件還包括一個 command: "write" 屬性,用於指定我們要透過此訊息觸發寫入操作。
  • 當點選清空檔案按鈕時,會執行 emptyOPFS()。此函式將包含 command: "empty" 屬性的物件傳送到 Worker,指定要清空檔案。
js
const writeBtn = document.querySelector(".write");
const emptyBtn = document.querySelector(".empty");
const fileText = document.querySelector("#file-text");

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

Worker JavaScript

Worker 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();

在 Worker 的 訊息事件 處理函式中,我們首先使用 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

瀏覽器相容性

另見