令人兴奋的浏览器文件系统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' 会打开桌面目录,还有其他可选的值包括 documents、downloads、music、pictures、videos 等。当然也可以是已知的文件或目录句柄。
  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的优势。

相关推荐
孟陬1 小时前
Foobar 技术周刊#160:大模型让大规模形式化软件验证成为现实丨AI写C++代码之后会发生什么?丨我们真的需要alpha() 函数吗丨重试,有时会让故障更
前端·后端·typescript
flash俊杰2 小时前
屏幕感知双通道:截图之外,为什么还要一份 UIA 控件清单
前端
熟的生菜2 小时前
从零造一个腱绳驱动灵巧手——仿真器篇3:VTK 渲染与 3D 交互——看得见、点得着、转得动
前端
Henry-SAP3 小时前
SAP PP中的核心业务流程——离散制造、重复制造、流程制造三大模式解析
前端·数据库·人工智能·制造
徐小夕3 小时前
下载量超 30 万的开源智能体 Prime Agent:它把自己从 TypeScript 重写成了 Rust
前端·vue.js·github
Zhao-Jichao3 小时前
AI Prompting for Everyone 课程笔记 - P20 实验与期末项目 Lab and Final Project
前端·人工智能·笔记
Moment4 小时前
为什么这么多 Agent Harness 都选择 TypeScript
前端·后端·面试
toooooop84 小时前
CRMEB 故障排查笔记:安全网关只放行 GET/POST 怎么办
前端·javascript·vue.js·thinkphp6·crmeb
涛涛ing4 小时前
我现在最怕的不是 AI 写不出代码,是它写得太快,快到我不好意思说“等一下”
前端
AllData公司负责人4 小时前
【产品便捷使用一】AIIData 数据中台:企业基础版核心能力支持,一站式全链路数据处理实操指南
大数据·前端·数据治理·数据可视化·数据开发·数据服务·数据接入