令人兴奋的浏览器文件系统API

在传统浏览器中,浏览器应用程序只能访问网页资源,而网页资源是存储在服务器上的。这意味着像 Photoshop、VSCode 等应用程序无法在浏览器中运行,因为它们需要访问本地文件。浏览器文件系统 API 的出现,打破了这一局限,为像 Photoshop、VSCode 等应用程序在浏览器中运行提供了基础。下面我们来看看浏览器怎么操作系统文件。

showOpenFilePicker 选取文件

showOpenFilePicker() 方法用于显示一个文件选择器,允许用户选择一个或多个文件。返回值是一个 File[] 数组,其中包含用户选择的文件句柄。当未指定任何选项时,只允许用户选择单个文件。

html 复制代码
<button @click="openFilePicker">打开文件</button>
js 复制代码
export default {
  methods: {
    async openFilePicker() {
      const [fileHandle] = await window.showOpenFilePicker()
      // 文件操作
    },
  },
}

点击按钮后,效果如下图所示:

读取文件

有了文件句柄,我们可以获取文件的属性,或者访问文件本身。通过getFile()获取 File 对象,然后通过 File 对象的方法(如slice()stream()text()arrayBuffer())来读取文件内容。

js 复制代码
const file = await fileHandle.getFile()
const contents = await file.text()

保存文件

showSaveFilePicker() 方法用于保存文件,可以创建一个新的文件,如创建一个空的 .txt 文件。

js 复制代码
async getNewFileHandle() {
  const options = {
    types: [
      {
        description: 'Text Files',
        accept: {
          'text/plain': ['.txt'],
        },
      },
    ],
  };
  const handle = await window.showSaveFilePicker(options);
  return handle;
}

以下是一些 options 的设置:

  1. suggestedName :设置默认文件名,例如 suggestedName: 'Untitled Text.txt'
  2. startIn :设置默认启动目录,例如 startIn: 'desktop' 会打开桌面目录,还有其他可选的值包括 documentsdownloadsmusicpicturesvideos 等。当然也可以是已知的文件或目录句柄。
  3. id :通过设置 id,可以让文件系统记住你打开过的目录位置。例如,当新建文件时设置id: "img",第一次选取了目录 /path/to/img,下次使用 id: "img" 时就能够直接定位到这个目录。

写入文件

要将数据写入磁盘,可以使用 FileSystemWritableFileStream 对象,它是 WritableStream 的一个子类。通过调用文件句柄对象创建流。在调用时,浏览器会首先检查用户是否已经授予对文件的写入权限。如果用户尚未授予写入权限,浏览器会提示用户进行授权。如果用户没有授权,则无法写入文件。

js 复制代码
async writeFile(fileHandle, contents) {
  // 创建一个 FileSystemWritableFileStream 用于写入
  const writable = await fileHandle.createWritable();
  // 写入我们的文件
  await writable.write(contents);
  // 关闭文件并将内容写入到磁盘
  await writable.close();
}

利用文件写入操作,还可以应用于流式下载文件。传统的文件下载方式使用 <a> 标签,需要加载完整文件,等待时间长,而且会消耗大量内存。使用流式下载就可以解决这个问题,而且可以摆脱依赖于像 StreamSaver.js 这样的库。

js 复制代码
async function writeURLToFile(fileHandle, url) {
  const writable = await fileHandle.createWritable()
  const response = await fetch(url)
  await response.body.pipeTo(writable)
}

showDirectoryPicker 选取目录

使用 showDirectoryPicker() 方法可以让用户选择一个目录,然后返回一个 FileSystemDirectoryHandle 对象。该目录句柄允许您枚举和访问该目录中的文件。默认情况下,您具有对目录中文件的读取权限,但如果需要写入权限,可以通过 { mode: 'readwrite' } 参数进行传递。

js 复制代码
async openDirectoryPicker() {
  const dirHandle = await window.showDirectoryPicker();
  for await (const entry of dirHandle.values()) {
    console.log(entry.kind, entry.name);
  }
}

创建文件夹或文件

对于已经存在的目录句柄,可以使用 getDirectoryHandle() 方法创建文件夹,或使用 getFileHandle() 方法创建文件。

js 复制代码
// 新建文件夹
const newDirectoryHandle = await existingDirectoryHandle.getDirectoryHandle('New Documents', {
  create: true,
})
// 新建文件
const newFileHandle = await newDirectoryHandle.getFileHandle('New Notes.txt', { create: true })

值得注意的是,使用 getFileHandle() 创建文件时不会弹出文件选择框,而是直接将文件添加到您的系统文件中,这一点与前面提到的保存新文件是不一样的。

删除文件夹或文件

可以使用 removeEntry() 方法来删除文件和文件夹。对于文件夹,可以选择递归删除,包括所有子文件夹和其中包含的文件。

js 复制代码
// 删除文件
await newDirectoryHandle.removeEntry('New Notes.txt')

// 删除文件夹
await existingDirectoryHandle.removeEntry('New Documents', { recursive: true })

还可以直接使用文件或文件夹句柄的 remove() 方法进行删除。

js 复制代码
await newDirectoryHandle.remove({ recursive: true })

await newFileHandle.remove()

删除目录时,如果目录不为空,需要添加 { recursive: true } 参数来递归删除子目录和文件,否则无法删除目录。

移动或重命名

可以使用 move() 方法来移动或重命名文件。实际上,重命名操作本质上也是一个移动操作。

js 复制代码
// 文件重命名为 Notes.txt
await newFileHandle.move('Notes.txt')
// 移动到新的文件夹
await newFileHandle.move(existingDirectoryHandle)
// 移动到新的文件夹并重命名为Notes.txt
await newFileHandle.move(existingDirectoryHandle, 'Notes.txt')

浏览器文件系统API的强大之处令人惊叹,它为未来浏览器应用程序的发展创造了广阔的前景。随着技术的不断进步,我们可以预见到更多应用程序将转移到浏览器平台,并利用文件操作API的优势。

相关推荐
gogoing2 分钟前
Prettier 配置说明
前端·javascript
十有八七3 分钟前
Hermes Agent 自进化实现:从源码到架构的深度拆解
前端·人工智能
渐儿3 分钟前
NestJS 生产级开发教程
前端
前端毕业班4 分钟前
uni-app onShareAppMessage hook 原理分析
前端·javascript
gogoing6 分钟前
React 分包加载优化
前端·react.js
gogoing8 分钟前
Babel 配置与工具
前端·javascript
亲亲小宝宝鸭9 分钟前
重新install,项目就跑不起来了?!
前端·npm
Mike117.22 分钟前
GBase 8a 物化视图依赖和 DDL 风险排查记录
java·服务器·前端
蜡台39 分钟前
Vue3 Hook 与 Store 状态管理:深度解析与选型指南
前端·javascript·vue.js
無名路人1 小时前
小程序点餐页吸顶滚动
前端·微信小程序·ai编程