FileSystemFileHandle: createWritable() 方法

基准线 2025
新推出

自 ⁨2025 年 9 月⁩起,此功能适用于最新设备和浏览器版本。此功能可能不适用于较旧的设备或浏览器。

安全上下文: 此功能仅在安全上下文(HTTPS)中可用,且支持此功能的浏览器数量有限。

注意:此功能在 Web Workers 中可用。

FileSystemFileHandle 接口的 createWritable() 方法创建一个 FileSystemWritableFileStream,该流可用于向文件写入数据。该方法返回一个 Promise,该 Promise 会解析为创建的流。

通过流进行的任何更改在流关闭之前都不会反映在文件句柄所表示的文件中。这通常是通过将数据写入临时文件来实现的,只有在可写文件流关闭时,才会用临时文件替换文件句柄所表示的文件。

语法

js
createWritable()
createWritable(options)

参数

options 可选

具有以下属性的对象:

keepExistingData 可选

一个 Boolean 值。默认为 false。如果设置为 true 且文件存在,则会将现有文件首先复制到临时文件中。否则,临时文件将从空开始。

mode 可选 非标准

一个字符串,指定可写文件流的锁定模式。默认值为 "siloed"。可能的值包括:

"exclusive"

一次只能打开一个 FileSystemWritableFileStream 写入器。在第一个写入器关闭之前尝试打开后续写入器将抛出 NoModificationAllowedError 异常。

"siloed"

可以同时打开多个 FileSystemWritableFileStream 写入器,每个写入器都有自己的交换文件,例如当同一应用程序在多个标签页中使用时。当每个写入器关闭并刷新数据时,最后一个打开的写入器的数据会被写入。

返回值

一个 Promise,它会解析为一个 FileSystemWritableFileStream 对象。

异常

NotAllowedError DOMException

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

NotFoundError DOMException

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

NoModificationAllowedError DOMException

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

AbortError DOMException

如果实现定义的恶意软件扫描和安全浏览检查失败,则抛出此异常。

示例

基本用法

以下异步函数会将给定内容写入文件句柄,进而写入磁盘。

js
async function writeFile(fileHandle, contents) {
  // Create a FileSystemWritableFileStream to write to.
  const writable = await fileHandle.createWritable();

  // Write the contents of the file to the stream.
  await writable.write(contents);

  // Close the file and write the contents to disk.
  await writable.close();
}

使用选项的扩展用法

我们的 createWritable() 模式测试 示例(请参阅 源代码)提供了一个 <button> 用于选择要写入的文件,一个文本 <input> 字段,您可以在其中输入要写入文件的文本,以及第二个 <button> 用于将文本写入文件。

在上面的演示中,请尝试选择文件系统上的一个文本文件(或输入一个新的文件名),在输入字段中输入一些文本,然后将文本写入文件。打开文件系统上的文件以检查写入是否成功。

另外,请尝试同时在两个浏览器标签页中打开该页面。在第一个标签页中选择一个要写入的文件,然后立即在第二个标签页中尝试选择同一个文件进行写入。您应该会收到一条错误消息,因为我们在 createWritable() 调用中设置了 mode: "exclusive"

下面我们将探讨代码。

HTML

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

html
<ol>
  <li>
    Select a file to write to: <button class="select">Select file</button>
  </li>
  <li>
    <label for="file-text">Enter text to write to the file:</label>
    <input type="text" id="file-text" name="file-text" disabled />
  </li>
  <li>
    Write your text to the file:
    <button class="write" disabled>Write text</button>
  </li>
</ol>

文本输入字段和写入文本按钮最初通过 disabled 属性设置为禁用状态——在用户选择要写入的文件之前不应使用它们。

JavaScript

我们首先获取对选择文件按钮、写入文本按钮和文本输入字段的引用。我们还声明了一个全局变量 writableStream,一旦创建,它将存储对用于将文本写入文件的可写流的引用。我们最初将其设置为 null

js
const selectBtn = document.querySelector(".select");
const writeBtn = document.querySelector(".write");
const fileText = document.querySelector("#file-text");

let writableStream = null;

接下来,我们创建一个名为 selectFile() 的异步函数,当按下选择按钮时调用它。此函数使用 Window.showSaveFilePicker() 方法向用户显示一个文件选择器对话框,并创建用户选择的文件的句柄。在该句柄上,我们调用 createWritable() 方法来创建一个将文本写入所选文件的流。如果调用失败,我们会将错误记录到控制台。

我们将 createWritable() 传递一个包含以下选项的对象:

  • keepExistingData: true:如果所选文件已存在,则在开始写入之前,会将其中包含的数据复制到临时文件中。
  • mode: "exclusive":表示一次只能打开一个写入器。如果第二个用户加载示例并尝试选择一个文件,他们将收到一个错误。

最后,我们启用输入字段和写入文本按钮,因为它们是下一步所必需的,并禁用选择文件按钮(当前不需要)。

js
async function selectFile() {
  // Create a new handle
  const handle = await window.showSaveFilePicker();

  // Create a FileSystemWritableFileStream to write to
  try {
    writableStream = await handle.createWritable({
      keepExistingData: true,
      mode: "exclusive",
    });
  } catch (e) {
    if (e.name === "NoModificationAllowedError") {
      console.log(
        `You can't access that file right now; someone else is trying to modify it. Try again later.`,
      );
    } else {
      console.log(e.message);
    }
  }

  // Enable text field and write button, disable select button
  fileText.disabled = false;
  writeBtn.disabled = false;
  selectBtn.disabled = true;
}

我们的下一个函数 writeFile() 使用 FileSystemWritableFileStream.write() 将输入字段中输入的文本写入所选文件,然后清空输入字段。然后我们使用 WritableStream.close() 关闭可写流,并重置演示以便再次运行——控件的 disabled 状态会切换回其原始状态,并且 writableStream 变量会重置为 null

js
async function writeFile() {
  // Write text to our file and empty out the text field
  await writableStream.write(fileText.value);
  fileText.value = "";

  // Close the file and write the contents to disk.
  await writableStream.close();

  // Disable text field and write button, enable select button
  fileText.disabled = true;
  writeBtn.disabled = true;
  selectBtn.disabled = false;

  // Set writableStream back to null
  writableStream = null;
}

为了运行演示,我们在按钮上设置了事件监听器,以便在每次单击按钮时运行相应的函数。

js
selectBtn.addEventListener("click", selectFile);
writeBtn.addEventListener("click", writeFile);

规范

规范
文件系统
# api-filesystemfilehandle-createwritable

浏览器兼容性

另见