diff --git a/files/zh-cn/web/api/file_system_api/index.md b/files/zh-cn/web/api/file_system_api/index.md
index d75d1aeb0686fc..d86af0fdbaccab 100644
--- a/files/zh-cn/web/api/file_system_api/index.md
+++ b/files/zh-cn/web/api/file_system_api/index.md
@@ -2,7 +2,7 @@
title: 文件系统 API
slug: Web/API/File_System_API
l10n:
- sourceCommit: 2b6bddfe281c0179fbde9c870f9de7c0dc3829e8
+ sourceCommit: 0c3f18aca2c8a93d3982183f64bf7762c2c310b0
---
{{securecontext_header}}{{DefaultAPISidebar("File System API")}}{{AvailableInWorkers}}
@@ -20,7 +20,7 @@ l10n:
你还可以从以下途径获得句柄:
- {{domxref('HTML Drag and Drop API', 'HTML 拖放 API', '', 'nocode')}} 的 {{domxref('DataTransferItem.getAsFileSystemHandle()')}} 方法。
-- [文件处理 API](https://developer.chrome.com/en/articles/file-handling/)。
+- [文件处理 API](https://developer.chrome.com/docs/capabilities/web-apis/file-handling)。
每种句柄都提供了其独有的功能,取决于你使用的种类,会有些许差异(详见[接口](#接口)部分)。在获得句柄后,你便可以访问文件的数据或是被选中的目录的信息(包含子目录)。此 API 开辟了 web 此前一直缺乏的潜在功能。但不论如何,安全性是设计 API 时的首要考量,除非用户明确授权,否则就不允许访问文件和目录的数据(注意:[源私有文件系统](#源私有文件系统)并非如此,因为其对用户不可见)。
diff --git a/files/zh-cn/web/api/file_system_api/origin_private_file_system/index.md b/files/zh-cn/web/api/file_system_api/origin_private_file_system/index.md
index 5628ce6b4c46f6..761775fa5423ca 100644
--- a/files/zh-cn/web/api/file_system_api/origin_private_file_system/index.md
+++ b/files/zh-cn/web/api/file_system_api/origin_private_file_system/index.md
@@ -2,7 +2,7 @@
title: 源私有文件系统
slug: Web/API/File_System_API/Origin_private_file_system
l10n:
- sourceCommit: 2b6bddfe281c0179fbde9c870f9de7c0dc3829e8
+ sourceCommit: 2cba64f68aab9e233fecfc2bab8bea4118716c14
---
{{securecontext_header}}{{DefaultAPISidebar("File System API")}}{{AvailableInWorkers}}
@@ -102,7 +102,7 @@ await (await navigator.storage.getDirectory()).remove({ recursive: true });
### 列出文件夹中的内容
-{{domxref("FileSystemDirectoryHandle")}} 是一个[异步迭代器](/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols#异步迭代器和异步可迭代协议)。所以,你可以用 [`for await…of`](/zh-CN/docs/Web/JavaScript/Reference/Statements/for-await...of) 循环和诸如 [`entries()`](/zh-CN/docs/Web/API/FileSystemDirectoryHandle/entries)、[`values()`](/zh-CN/docs/Web/API/FileSystemDirectoryHandle/entries) 和 [`keys()`](/zh-CN/docs/Web/API/FileSystemDirectoryHandle/entries) 这样的标准方法对其进行迭代。
+{{domxref("FileSystemDirectoryHandle")}} 是一个[异步迭代器](/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols#异步迭代器和异步可迭代协议)。所以,你可以用 [`for await...of`](/zh-CN/docs/Web/JavaScript/Reference/Statements/for-await...of) 循环和诸如 [`entries()`](/zh-CN/docs/Web/API/FileSystemDirectoryHandle/entries)、[`values()`](/zh-CN/docs/Web/API/FileSystemDirectoryHandle/entries) 和 [`keys()`](/zh-CN/docs/Web/API/FileSystemDirectoryHandle/entries) 这样的标准方法对其进行迭代。
例如:
@@ -179,7 +179,7 @@ size = accessHandle.getSize();
const dataView = new DataView(new ArrayBuffer(size));
// 将整个文件读取到数据视图。
-accessHandle.read(dataView);
+accessHandle.read(dataView, { at: 0 });
// 打印 `"Some textMore content"`。
console.log(textDecoder.decode(dataView));
diff --git a/files/zh-cn/web/api/filesystemdirectoryhandle/index.md b/files/zh-cn/web/api/filesystemdirectoryhandle/index.md
index e29b303201ccc3..be6f060a35b590 100644
--- a/files/zh-cn/web/api/filesystemdirectoryhandle/index.md
+++ b/files/zh-cn/web/api/filesystemdirectoryhandle/index.md
@@ -2,7 +2,7 @@
title: FileSystemDirectoryHandle
slug: Web/API/FileSystemDirectoryHandle
l10n:
- sourceCommit: be3c45cd7a4d5c04139eceae10f7368251cdca64
+ sourceCommit: e92950d09467164afc9dfd8b35be9c909b63a8ab
---
{{securecontext_header}}{{APIRef("File System API")}}{{AvailableInWorkers}}
diff --git a/files/zh-cn/web/api/filesystemfilehandle/createsyncaccesshandle/index.md b/files/zh-cn/web/api/filesystemfilehandle/createsyncaccesshandle/index.md
index 1812ba74b57b24..e4883e512dfe1c 100644
--- a/files/zh-cn/web/api/filesystemfilehandle/createsyncaccesshandle/index.md
+++ b/files/zh-cn/web/api/filesystemfilehandle/createsyncaccesshandle/index.md
@@ -2,7 +2,7 @@
title: FileSystemFileHandle:createSyncAccessHandle() 方法
slug: Web/API/FileSystemFileHandle/createSyncAccessHandle
l10n:
- sourceCommit: f10fbe2d2dc4857bf29ce955689a7ba7c1ffac8b
+ sourceCommit: 2b6f99e45534ce662f842d8b4d2f7845492e353c
---
{{securecontext_header}}{{APIRef("File System API")}}{{AvailableInWorkers("dedicated")}}
@@ -15,11 +15,23 @@ l10n:
```js-nolint
createSyncAccessHandle()
+createSyncAccessHandle(options)
```
### 参数
-无。
+- `options` {{optional_inline}}
+
+ - : 一个具有以下属性的对象:
+
+ - `mode` {{optional_inline}} {{non-standard_inline}}
+ - : 指定访问句柄的锁定模式的字符串。默认值为 `"readwrite"`。可能的值包括:
+ - `"read-only"`
+ - : 可以同时在一个文件上打开多个 `FileSystemSyncAccessHandle` 对象(例如,在多个标签页中使用同一个应用时),前提是它们都以 `"read-only"` 模式打开。打开后,可以在句柄上调用类似读取的方法——{{domxref("FileSystemSyncAccessHandle.read", "read()")}}、{{domxref("FileSystemSyncAccessHandle.getSize", "getSize()")}} 和 {{domxref("FileSystemSyncAccessHandle.close", "close()")}}。
+ - `"readwrite"`
+ - : 每个文件只能打开一个 `FileSystemSyncAccessHandle` 对象。如果在第一个句柄关闭之前尝试打开后续句柄,则会导致抛出 `NoModificationAllowedError` 异常。打开后,可以调用句柄上的任何可用方法。
+ - `"readwrite-unsafe"`
+ - : 可以同时在一个文件上打开多个 `FileSystemSyncAccessHandle` 对象,前提是它们都以 `"readwrite-unsafe"` 模式打开。打开后,可以在句柄上调用任何可用的方法。
### 返回值
@@ -34,10 +46,12 @@ createSyncAccessHandle()
- `NotFoundError` {{domxref("DOMException")}}
- : 如果未找到当前条目,则抛出该异常。
- `NoModificationAllowedError` {{domxref("DOMException")}}
- - : 如果浏览器无法获得文件句柄所关联的文件的锁定,抛出此异常。
+ - : 如果浏览器无法获得文件句柄所关联的文件的锁定,抛出此异常。这可能是因为 `mode` 被设置为 `readwrite`,并尝试同时打开多个句柄。
## 示例
+### 基本用法
+
以下异步事件处理函数处于 Web Worker 上下文。其中的代码片段创建了一个同步文件访问句柄。
```js
@@ -58,6 +72,134 @@ onmessage = async (e) => {
};
```
+### 带有 `mode` 选项的完整示例
+
+我们的 [`createSyncAccessHandle()` 模式测试](https://createsyncaccesshandle-mode-test.glitch.me/)示例提供了一个 {{htmlelement("input")}} 字段来输入文本,以及两个按钮——一个用于将输入的文本写入原始私有文件系统中的文件末尾,另一个用于在文件太满时清空文件。
+
+尝试探索上面的演示,打开浏览器开发者控制台,以便你可以看到正在发生的事情。如果你尝试在多个浏览器标签页中打开演示,你会发现可以同时打开多个句柄以同时写入文件。这是因为在 `createSyncAccessHandle()` 调用上设置了 `mode: "readwrite-unsafe"`。
+
+下面我们将探索代码。
+
+#### HTML
+
+两个 {{htmlelement("button")}} 元素和文本 {{htmlelement("input")}} 字段如下所示:
+
+```html
+
+ -
+
+
+
+ - 将你的文本写入文件:
+ - 如果文件太满,则清空该文件:
+
+```
+
+#### 主线程 JavaScript
+
+HTML 文件中的主线程 JavaScript 如下所示。我们获取对写入文本按钮、清空文件按钮和文本输入字段的引用,然后使用 {{domxref("Worker.Worker", "Worker()")}} 构造函数创建一个新的 Web Worker。然后我们定义两个函数并将它们设置为按钮上的事件处理器:
+
+- 单击写入文本按钮时运行 `writeToOPFS()`。此函数使用 {{domxref("Worker.postMessage()")}} 方法将文本字段的输入值发布到对象内的 Worker,然后清空文本字段,为下一次添加做好准备。请注意传递的对象还包含 `command: "write"` 属性,以指定我们想要使用此消息触发写入操作。
+- 单击清空文件按钮时运行 `emptyOPFS()`。这会将包含 `command: "empty"` 属性的对象发布到 Worker,指定要清空文件。
+
+```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("主线程脚本:发送给 worker 的文本");
+ fileText.value = "";
+}
+
+function emptyOPFS() {
+ opfsWorker.postMessage({
+ command: "empty",
+ });
+}
+
+writeBtn.addEventListener("click", writeToOPFS);
+emptyBtn.addEventListener("click", emptyOPFS);
+```
+
+#### Worker 线程 JavaScript
+
+worker JavaScript 如下所示。
+
+首先,我们运行一个名为 `initOPFS()` 的函数,该函数使用 {{domxref("StorageManager.getDirectory()")}} 获取对 OPFS 根的引用,使用 {{domxref("FileSystemDirectoryHandle.getFileHandle()")}} 创建文件并返回其句柄,然后使用 `createSyncAccessHandle()` 返回 {{domxref("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 的 [message 事件](/zh-CN/docs/Web/API/Worker/message_event)处理器中,我们首先使用 {{domxref("FileSystemSyncAccessHandle.getSize", "getSize()")}} 获取文件的大小。然后,我们检查消息中发送的数据是否包含 `command` 属性值 `"empty"`。如果是,我们使用 {{domxref("FileSystemSyncAccessHandle.truncate", "truncate()")}} 清空文件,值为 `0`,并更新 `size` 变量中包含的文件大小。
+
+如果消息数据是其他内容,我们:
+
+- 创建新的 {{domxref("TextEncoder")}} 和 {{domxref("TextDecoder")}} 来处理稍后对文本内容的编码和解码。
+- 使用 {{domxref("FileSystemSyncAccessHandle.write", "write()")}} 对消息数据进行编码并将结果写入文件末尾,然后更新 `size` 变量中包含的文件大小。
+- 创建一个 {{jsxref("DataView")}} 来包含文件内容,并使用 {{domxref("FileSystemSyncAccessHandle.read", "read()")}} 将内容读入其中。
+- 解码 `DataView` 内容并将其记录到控制台。
+
+```js
+onmessage = function (e) {
+ console.log("Worker:从主线程收到消息");
+
+ // 获取文件当前大小
+ let size = accessHandle.getSize();
+
+ if (e.data.command === "empty") {
+ // 将文件截断为 0 字节
+ accessHandle.truncate(0);
+
+ // 获取文件当前大小
+ size = accessHandle.getSize();
+ } else {
+ const textEncoder = new TextEncoder();
+ const textDecoder = new TextDecoder();
+
+ // 对要写入文件的内容进行编码
+ const content = textEncoder.encode(e.data.content);
+ // 在文件末尾写入内容
+ accessHandle.write(content, { at: size });
+
+ // 获取文件当前大小
+ size = accessHandle.getSize();
+
+ // 准备文件长度的数据视图
+ const dataView = new DataView(new ArrayBuffer(size));
+
+ // 将整个文件读入数据视图
+ accessHandle.read(dataView, { at: 0 });
+
+ // 将当前文件内容记录到控制台
+ console.log("文件内容:" + textDecoder.decode(dataView));
+
+ // 刷新更改
+ accessHandle.flush();
+ }
+
+ // 将文件的大小记录到控制台
+ console.log("大小:" + size);
+};
+```
+
## 规范
{{Specifications}}
diff --git a/files/zh-cn/web/api/filesystemfilehandle/createwritable/index.md b/files/zh-cn/web/api/filesystemfilehandle/createwritable/index.md
index 0f20a7615f6136..cd3703d5e4f4ca 100644
--- a/files/zh-cn/web/api/filesystemfilehandle/createwritable/index.md
+++ b/files/zh-cn/web/api/filesystemfilehandle/createwritable/index.md
@@ -2,7 +2,7 @@
title: FileSystemFileHandle:createWritable() 方法
slug: Web/API/FileSystemFileHandle/createWritable
l10n:
- sourceCommit: f10fbe2d2dc4857bf29ce955689a7ba7c1ffac8b
+ sourceCommit: 1a7695e13c51d85a81e3e5d85feedbc5dbd2a379
---
{{securecontext_header}}{{APIRef("File System API")}}{{AvailableInWorkers}}
@@ -26,6 +26,12 @@ createWritable(options)
- `keepExistingData` {{optional_inline}}
- : {{jsxref('Boolean', '布尔值', '', 'nocode')}},默认为 `false`。当设为 `true` 时,如果文件存在,则现将现有文件的内容复制到临时文件,否则临时文件初始时内容为空。
+ - `mode` {{optional_inline}} {{non-standard_inline}}
+ - : 指定可写文件流的锁定模式的字符串。默认值为 `"siloed"`。可能的值包括:
+ - `"exclusive"`
+ - : 只能打开一个 `FileSystemWritableFileStream` 写入器。在第一个写入器关闭之前尝试打开后续写入器会导致抛出 `NoModificationAllowedError` 异常。
+ - `"siloed"`
+ - : 可以同时打开多个 `FileSystemWritableFileStream` 写入器,每个写入器都有自己的交换文件,例如在多个标签页中使用同一个应用时。最后打开的写入器会写入其数据,因为每个写入器关闭时都会刷新数据。
### 返回值
@@ -38,12 +44,14 @@ createWritable(options)
- `NotFoundError` {{domxref("DOMException")}}
- : 如果未找到当前条目,则抛出该异常。
- `NoModificationAllowedError` {{domxref("DOMException")}}
- - : 如果浏览器无法获取与文件句柄关联的文件的锁,则抛出该异常。
+ - : 如果浏览器无法获取与文件句柄关联的文件的锁,则抛出该异常。这可能是因为 `mode` 设置为 `exclusive`,并且尝试同时打开多个写入器。
- `AbortError` {{domxref("DOMException")}}
- : 如果实现定义的恶意软件扫描和安全浏览检查失败,则抛出此异常。
## 示例
+### 基本用法
+
以下异步函数用于将给定内容写入文件句柄,从而写入磁盘。
```js
@@ -59,6 +67,115 @@ async function writeFile(fileHandle, contents) {
}
```
+### 通过选项扩展用途
+
+我们的 [`createWritable()` 模式测试](https://createwritable-mode-test.glitch.me/)示例提供了一个 {{htmlelement("button")}} 来选择要写入的文件,一个文本 {{htmlelement("input")}} 字段,你可以在其中输入一些要写入文件的文本,以及第二个 `