File System Access API

文件系统访问 API 是一种网页 API, 允许访问和修改用户本地的文件。它为构建强大的网页应用打开了新的可能,例如文本编辑器、IDE、图像处理软件,也可以轻松实现导入与导出功能,所有这些都可以在网页前端实现。下面让我们一起来看看如何开始使用这个 API。

使用文件系统访问 API 读取文件

在我们深入研究从用户系统中读取文件的代码之前,有一个很重要的细节需要牢记:调用文件系统访问 API 必须通过用户操作触发,并在安全的上下文中进行。 在下面的例子中,我们将在点击事件中调用该 API。

读取单个文件

从一个文件中读取数据,代码不到 10 行就可以实现。下面是一个示例:

ini 复制代码
 let fileHandle;

 document.querySelector(".pick-file").onclick = async () => {
  [fileHandle] = await window.showOpenFilePicker();

  const file = await fileHandle.getFile();
  const content = await file.text();

  return content;
 };

假设我们在 HTML 中有一个 class 为 .pick-file 的按钮。当点击这个按钮时,我们通过调用 window.showOpenFilePicker() 启动文件选择器,并将返回结果存储在一个名为 fileHandle 的变量中。

调用 showOpenFilePicker() 返回的是表示所选文件的 FileSystemFileHandle 对象数组。由于这个例子只选择单个文件,我们会解构这个结果。关于选择多个文件我稍后会介绍。

这些对象包含 kind 和 name 属性。如果打印 console.log(fileHandle), 你会看到如下对象:

css 复制代码
 FileSystemFileHandle {kind: 'file', name: 'data.txt'}

kind 属性的值可以是 file 或者 directory。

在 fileHandle 对象上,我们可以调用 getFile () 方法来获取文件详情。调用这个方法会返回一个对象,包含文件最后修改时间、文件名、大小和类型等属性。

最后,我们可以在文件对象上调用 text () 方法获取文件内容。

读取多个文件

如果要读取多个文件,我们需要向 showOpenFilePicker () 传入一个 options 对象。

例如:

dart 复制代码
 let fileHandles;
 const options = {
  multiple: true,
 };

 document.querySelector(".pick-file").onclick = async () => {
  fileHandles = await window.showOpenFilePicker(options);

  // The rest of the code will be shown below
 };

默认情况下,multiple 属性为 false。我们还可以通过选项指明可选择的文件类型。

例如,如果只希望选择 .jpeg 文件,options 对象会包含以下内容:

css 复制代码
 const options = {
  types: [
    {
      description: "Images",
      accept: {
        "image/jpeg": ".jpeg",
      },
    },
  ],
  excludeAcceptAllOption: true,
 };

在这个例子中,fileHandles 是一个包含多个文件的数组,获取内容的方法如下:

ini 复制代码
 let fileHandles;
 const options = {
  multiple: true,
 };

 document.querySelector(".pick-file").onclick = async () => {
  fileHandles = await window.showOpenFilePicker(options);

  const allContent = await Promise.all(
    fileHandles.map(async (fileHandle) => {
      const file = await fileHandle.getFile();
      const content = await file.text();
      return content;
    })
  );

  console.log(allContent);
 };

使用文件系统访问 API 写入文件

文件系统访问 API 也允许您向文件写入内容。首先,让我们看一下如何保存新文件。

写入新文件

向新文件写入也可以用很少的代码实现!

dart 复制代码
 document.querySelector(".save-file").onclick = async () => {
  const options = {
    types: [
      {
        description: "Test files",
        accept: {
          "text/plain": [".txt"],
        },
      },
    ],
  };

  const handle = await window.showSaveFilePicker(options);
  const writable = await handle.createWritable();

  await writable.write("Hello World");
  await writable.close();

  return handle;
 };

假设我们有第二个 class 为 save-file 的按钮,点击时,通过 showSaveFilePicker() 方法打开文件选择器,并在 options 对象中指明要保存的文件类型,这里是 .txt 文件。

调用这个方法同样会返回一个 FileSystemFileHandle 对象,就像第一部分一样。在这个对象上调用 createWritable() 方法会返回一个 FileSystemWritableFileStream 对象。然后我们可以通过 write() 方法往这个流里写入内容。

最后,需要调用 close() 方法来关闭文件,完成内容写入。

例如,如果要写入 HTML 代码到文件,只需要在 options 对象里将内容类型设为 "text/html" , 调用 write () 方法传入 HTML 内容即可。

编辑现有文件

如果要导入一个文件并用文件系统访问 API 编辑,示例代码如下:

ini 复制代码
 let fileHandle;

 document.querySelector(".pick-file").onclick = async () => {
  [fileHandle] = await window.showOpenFilePicker();

  const file = await fileHandle.getFile();
  const writable = await fileHandle.createWritable();

  await writable.write("This is a new line");
  await writable.close();
 };

如果你已经阅读过前面的内容,可能会注意到我们首先通过 showOpenFilePicker()getFile() 方法读取一个文件,然后用 createWritable()write()close() 方法写入同一个文件。

如果导入的文件已经包含一些内容,这个代码会用传给 write() 方法的新内容替换原有的文件内容。

文件系统访问 API 的其他功能

这里不详细展开,文件系统访问 API 还可以列出目录中的文件,以及删除文件和目录。

读取目录

读取目录只需要很少的代码:

dart 复制代码
 document.querySelector(".read-dir").onclick = async () => {
  const directoryHandle = await window.showDirectoryPicker();

  for await (const entry of directoryHandle.values()) {
    console.log(entry.kind, entry.name);
  }
 };

如果我们添加一个新的 class 为 .read-dir 的按钮,点击时调用 showDirectoryPicker () 方法会打开文件选择器,选择计算机上的一个目录后,这段代码会列出该目录中的文件。

删除文件

可以用以下代码删除一个目录中的文件:

dart 复制代码
 document.querySelector(".pick-file").onclick = async () => {
  const [fileHandle] = await window.showOpenFilePicker();
  await fileHandle.remove();
 };

如果您想删除一个文件夹,只需对上述代码示例做一个小修改即可:

dart 复制代码
 document.querySelector(".read-dir").onclick = async () => {
  const directoryHandle = await window.showDirectoryPicker();
  await directoryHandle.remove();
 };

最后,如果您在选择文件夹时想要删除一个特定文件,可以这样写:

dart 复制代码
 // Delete a single file named data.txt in the selected folder
 document.querySelector(".pick-folder").onclick = async () => {
    const directoryHandle = await window.showDirectoryPicker();
    await directoryHandle.removeEntry("data.txt");
 };

如果想删除整个文件夹,需要以下代码:

dart 复制代码
 // Recursively delete the folder named "data"
 document.querySelector(".pick-folder").onclick = async () => {
    const directoryHandle = await window.showDirectoryPicker();
    await directoryHandle.removeEntry('data', { recursive: true });
 };

File System Access API 浏览器支持情况

目前,IE 和 Firefox 浏览器似乎都不支持 File System Access API。不过,存在一个名为 browser-fs-access 的腻子 (polyfill)。

总结

如果你想要尝试 File System Access API, 可以查看谷歌工程师开发的这个在线演示文本编辑器。另外,如果你想学习更多关于这个 API 及其所有功能的信息,这里有一些资源:

  • File System Access API (W3C 规范)
  • File System Access API (MDN)
  • 对比度范围,replaceAll 方法,原生文件系统 API (Šime Vidas)
  • File System Access API: 简化访问本地文件的操作 (web.dev)
  • 使用 browser-fs-access 库读取和写入文件与目录 (web.dev)
  • browser-fs-access 仓库 (GitHub)
相关推荐
golitter.9 分钟前
Ajax和axios简单用法
前端·ajax·okhttp
雷特IT29 分钟前
Uncaught TypeError: 0 is not a function的解决方法
前端·javascript
长路 ㅤ   1 小时前
vite学习教程02、vite+vue2配置环境变量
前端·vite·环境变量·跨环境配置
亚里士多没有德7751 小时前
强制删除了windows自带的edge浏览器,重装不了怎么办【已解决】
前端·edge
micro2010141 小时前
Microsoft Edge 离线安装包制作或获取方法和下载地址分享
前端·edge
.生产的驴1 小时前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
awonw1 小时前
[前端][easyui]easyui select 默认值
前端·javascript·easyui
九圣残炎2 小时前
【Vue】vue-admin-template项目搭建
前端·vue.js·arcgis
柏箱2 小时前
使用JavaScript写一个网页端的四则运算器
前端·javascript·css
TU^2 小时前
C语言习题~day16
c语言·前端·算法