文件系统 API

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

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

文件系统 API — 通过 文件系统访问 API 提供的扩展来访问设备文件系统上的文件 — 允许读取、写入和文件管理功能。

概念和用法

此 API 允许与用户本地设备或用户可访问的网络文件系统上的文件交互。此 API 的核心功能包括读取文件、写入或保存文件以及访问目录结构。

大多数与文件和目录的交互都是通过句柄完成的。父 FileSystemHandle 类有助于定义两个子类:FileSystemFileHandleFileSystemDirectoryHandle,分别用于文件和目录。

句柄表示用户系统上的文件或目录。你可以首先使用 window.showOpenFilePicker()window.showDirectoryPicker() 等方法向用户显示文件或目录选择器来获取访问权限。调用这些方法后,文件选择器将显示出来,用户可以选择文件或目录。如果成功,则返回一个句柄。

你也可以通过以下方式获取文件句柄访问权限:

每个句柄都提供自己的功能,并且根据你使用的是哪个句柄,存在一些差异(有关具体细节,请参阅 接口 部分)。然后,你可以访问文件数据或所选目录的信息(包括子目录)。此 API 开放了 Web 一直缺乏的潜在功能。然而,在设计 API 时,安全性一直是首要考虑因素,除非用户明确允许,否则不允许访问文件/目录数据(请注意,源代码专用文件系统 并非如此,因为它对用户不可见)。

注意:使用此 API 功能时可能引发的不同异常在规范中相关页面的定义中列出。但是,API 与底层操作系统的交互会使情况更加复杂。已经提出了一份建议,在规范中列出错误映射,其中包括有用的相关信息。

注意:基于 FileSystemHandle 的对象也可以序列化到 IndexedDB 数据库实例中,或者通过 postMessage() 传输。

源代码专用文件系统

源代码专用文件系统 (OPFS) 是作为文件系统 API 的一部分提供的存储端点,该端点对页面的源代码专用,对用户不可见,就像常规文件系统一样。它提供对一种特殊文件的访问权限,这种文件针对性能进行了高度优化,并提供对内容的原地写入访问权限。

阅读我们的 源代码专用文件系统,了解如何使用它。

保存文件

  • 对于异步句柄,请使用 FileSystemWritableFileStream 接口。一旦你想要保存的数据以 BlobString 对象、字符串文字或 buffer 的格式存在,你就可以打开一个流并将数据保存到文件中。这可以是现有文件或新文件。
  • 对于同步 FileSystemSyncAccessHandle,你可以使用 write() 方法将更改写入文件。你也可以选择调用 flush(),如果你需要在特定时间将更改提交到磁盘(否则,你可以让底层操作系统在适当的时候处理它,这在大多数情况下应该没问题)。

接口

FileSystemHandle

表示文件或目录条目的对象。多个句柄可以表示相同的条目。在大多数情况下,你不会直接使用 FileSystemHandle,而是使用它的子接口 FileSystemFileHandleFileSystemDirectoryHandle

FileSystemFileHandle

提供对文件系统条目的句柄。

FileSystemDirectoryHandle

提供对文件系统目录的句柄。

FileSystemSyncAccessHandle

提供对文件系统条目的同步句柄,它在磁盘上的单个文件上就地操作。文件读取和写入的同步性质允许在异步操作开销较高的上下文中(例如,WebAssembly)对关键方法进行更高性能的操作。此类仅在专用的 Web Workers 中对 源代码专用文件系统 中的文件可用。

FileSystemWritableFileStream

一个带有额外便利方法的 WritableStream 对象,它对磁盘上的单个文件进行操作。

对其他接口的扩展

Window.showDirectoryPicker()

显示一个目录选择器,允许用户选择一个目录。

Window.showOpenFilePicker()

显示一个文件选择器,允许用户选择一个或多个文件。

Window.showSaveFilePicker()

显示一个文件选择器,允许用户保存一个文件。

DataTransferItem.getAsFileSystemHandle()

如果拖动的项目是文件,则返回 FileSystemFileHandle;如果拖动的项目是目录,则返回 FileSystemDirectoryHandle

StorageManager.getDirectory()

用于获取对 FileSystemDirectoryHandle 对象的引用,该对象允许访问存储在 源代码专用文件系统 中的目录及其内容。返回一个 Promise,它使用 FileSystemDirectoryHandle 对象来满足。

示例

访问文件

以下代码允许用户从文件选择器中选择一个文件。

js
async function getFile() {
  // Open file picker and destructure the result the first handle
  const [fileHandle] = await window.showOpenFilePicker();
  const file = await fileHandle.getFile();
  return file;
}

以下异步函数显示一个文件选择器,一旦选择了文件,就会使用 getFile() 方法检索内容。

js
const pickerOpts = {
  types: [
    {
      description: "Images",
      accept: {
        "image/*": [".png", ".gif", ".jpeg", ".jpg"],
      },
    },
  ],
  excludeAcceptAllOption: true,
  multiple: false,
};

async function getTheFile() {
  // Open file picker and destructure the result the first handle
  const [fileHandle] = await window.showOpenFilePicker(pickerOpts);

  // get file contents
  const fileData = await fileHandle.getFile();
}

访问目录

以下示例返回具有指定名称的目录句柄。如果目录不存在,则创建它。

js
const dirName = "directoryToGetName";

// assuming we have a directory handle: 'currentDirHandle'
const subDir = currentDirHandle.getDirectoryHandle(dirName, { create: true });

以下异步函数使用 resolve() 查找所选文件的路径,该路径相对于指定的目录句柄。

js
async function returnPathDirectories(directoryHandle) {
  // Get a file handle by showing a file picker:
  const [handle] = await self.showOpenFilePicker();
  if (!handle) {
    // User cancelled, or otherwise failed to open a file.
    return;
  }

  // Check if handle exists inside our directory handle
  const relativePaths = await directoryHandle.resolve(handle);

  if (relativePaths === null) {
    // Not inside directory handle
  } else {
    // relativePaths is an array of names, giving the relative path

    for (const name of relativePaths) {
      // log each entry
      console.log(name);
    }
  }
}

写入文件

以下异步函数打开保存文件选择器,该选择器会在选择文件后返回一个 FileSystemFileHandle。然后,使用 FileSystemFileHandle.createWritable() 方法创建一个可写流。

然后,将用户定义的 Blob 写入流,随后关闭流。

js
async function saveFile() {
  // create a new handle
  const newHandle = await window.showSaveFilePicker();

  // create a FileSystemWritableFileStream to write to
  const writableStream = await newHandle.createWritable();

  // write our file
  await writableStream.write(imgBlob);

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

以下显示了可以传递到 write() 方法中的不同选项示例。

js
// just pass in the data (no options)
writableStream.write(data);

// writes the data to the stream from the determined position
writableStream.write({ type: "write", position, data });

// updates the current file cursor offset to the position specified
writableStream.write({ type: "seek", position });

// resizes the file to be size bytes long
writableStream.write({ type: "truncate", size });

在 OPFS 中同步读取和写入文件

此示例同步地将文件读取到 源代码专用文件系统 中,并写入该系统。

以下异步事件处理程序函数包含在 Web Worker 中。在收到来自主线程的消息时,它会:

  • 创建一个同步文件访问句柄。
  • 获取文件的大小并创建一个 ArrayBuffer 来容纳它。
  • 将文件内容读取到缓冲区中。
  • 对消息进行编码并将其写入文件的末尾。
  • 将更改持久保存到磁盘并关闭访问句柄。
js
onmessage = async (e) => {
  // retrieve message sent to work from main script
  const message = e.data;

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

  // Get size of the file.
  const fileSize = accessHandle.getSize();
  // Read file content to a buffer.
  const buffer = new DataView(new ArrayBuffer(fileSize));
  const readBuffer = accessHandle.read(buffer, { at: 0 });

  // Write the message to the end of the file.
  const encoder = new TextEncoder();
  const encodedMessage = encoder.encode(message);
  const writeBuffer = accessHandle.write(encodedMessage, { at: readBuffer });

  // Persist changes to disk.
  accessHandle.flush();

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

注意:在规范的早期版本中,close()flush()getSize()truncate() 非人性化地被指定为异步方法。现在已经 进行了修正,但一些浏览器仍然支持异步版本。

规范

规范
文件系统标准
文件系统访问

浏览器兼容性

api.FileSystemHandle

BCD 表格仅在浏览器中加载

api.FileSystemFileHandle

BCD 表格仅在浏览器中加载

api.FileSystemDirectoryHandle

BCD 表格仅在浏览器中加载

api.FileSystemWritableFileStream

BCD 表格仅在浏览器中加载

api.FileSystemSyncAccessHandle

BCD 表格仅在浏览器中加载

另请参阅