FileSystemFileHandle: createSyncAccessHandle() 方法
注意:此功能仅在 专用 Web Worker 中可用。
FileSystemFileHandle
接口的 createSyncAccessHandle()
方法返回一个 Promise
,该 Promise 解析为一个 FileSystemSyncAccessHandle
对象,可用于同步地读取和写入文件。此方法的同步性带来了性能优势,但它只能在专用 Web Worker 中用于 源私有文件系统 内的文件。
创建 FileSystemSyncAccessHandle
会对与文件句柄关联的文件进行独占锁定。这会阻止在现有访问句柄关闭之前为该文件创建进一步的 FileSystemSyncAccessHandle
或 FileSystemWritableFileStream
。
语法
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.state
在readwrite
模式下不是granted
,则抛出此异常。 InvalidStateError
DOMException
-
如果
FileSystemSyncAccessHandle
对象不代表 源私有文件系统 中的文件,则抛出此异常。 NotFoundError
DOMException
-
如果当前条目未找到,则抛出此异常。
NoModificationAllowedError
DOMException
-
如果浏览器无法获取与文件句柄关联文件的锁定,则抛出此异常。这可能是因为
mode
设置为readwrite
,并且尝试同时打开多个句柄。
示例
基本用法
以下异步事件处理函数包含在 Web Worker 中。其中的代码片段会创建一个同步文件访问句柄。
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>
字段如下所示:
<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,指定要清空文件。
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"
属性,允许多个句柄同时访问同一文件。
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
变量中包含的文件大小。
如果消息数据是其他内容,我们则
- 创建一个新的
TextEncoder
和TextDecoder
,以便稍后处理文本内容的编码和解码。 - 编码消息数据,并使用
write()
将结果写入文件末尾,然后更新size
变量中包含的文件大小。 - 创建一个
DataView
来包含文件内容,并使用read()
将内容读取到其中。 - 解码
DataView
内容并将其记录到控制台。
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 |
浏览器兼容性
加载中…