在浏览器中用 JS 管理文件

现代浏览器能做比我们平常所知道的更多的事情。今天,我将会介绍一个在服务端编程领域很熟悉,但是在前端开发领域很少被人提及的话题:访问文件系统并管理文件和文件夹

是的,你没听错,文件系统的管理在现代浏览器中通过 JavaScript 进行是可行的,只需要通过其提供的文件系统 API。然而,这组 API 是很原始且偏向底层的。如果有更便捷的操作方式,如同我们在 Node.js 中那样,就好了。用另外的话来说,我们需要更高级的 API 来操作文件系统。我们将在接下来的示例中介绍它们。

如果你已经在桌面端的 Chrome 浏览器中,你可以按下 F12 来打开 Chrome 开发者工具并切换到 Console 面板,因为我们接下来的示例将直接运行在 Chrome 的控制台中。你可以直接复制给出的代码并粘贴到控制台中来自行查看实际的效果。如果你不在 Chrome 浏览器中,你也可以只阅读这些示例,它们本身也是非常易于理解的。

导入 fs 模块

由于我们在 Chrome 控制台中,我们需要使用 import() 函数来远程导入 fs 模块。

const fs = await import("https://ayonli.github.io/jsext/esm/fs.js")
JavaScript

如果我们是在编写一个 JavaScript 模块文件,我们则应该使用 import 语句来导入。

import * as fs from "https://ayonli.github.io/jsext/esm/fs.js"
// or with a package manager
import * as fs from "@ayonli/jsext/fs"
JavaScript

取得根目录

在浏览器中,文件系统 API 默认会使用源私有文件系统,我们不需要做任何特别操作就能过使用它,就像 Node.js 一样。然而,正如我前面所说,在这篇文章中,我们将会操作计算机上真实的文件系统,因此我们将需要取得一个目录句柄并将它传入到将使用的函数中。

const root = await window.showDirectoryPicker()
JavaScript

这行代码将会打开一个对话框,允许我们选择一个系统里的文件夹用于操作。在这里,我选择了一个位于 ~/Public 中名称为 demo 的文件夹,来做演示,它将会被用作为这篇文章的后续示例中的根目录。

浏览器会弹出一个确认对话框,询问是否允许网站查看所选文件夹的内容,直接点击 查看文件 按钮来允许。

读取根目录下的文件条目

现在我们拥有了一个根目录的句柄,我们可以使用熟悉的 API 来访问它里面的内容。首先,让我们看一下它里面现在有什么。

const entries = await Array.fromAsync(fs.readDir("/", { root }))
console.log(entries)
JavaScript

上面的代码将会打印所有 root 目录中的文件和文件夹。由于我所选择的目录现在是空的,此代码将会在控制台中打印一个空数组。

除此之外,我们还可以使用 readTree 函数来获取目录的树形结构。

const tree = await fs.readTree("/", { root })
console.log(tree)
JavaScript

我的控制台打印了如下的内容:

创建一个子目录

为了便于演示,我将会在 root 目录下创建一个名为 foo 的文件夹,并将其他的文件存放在它里面。

await fs.mkdir("/foo", { root })
JavaScript

浏览器会弹出另一个对话框询问是否允许网站保存对 root 目录的更改,只需要点击 保存修改 按钮允许即可。

现在,如果我再次运行 readTree 函数,我们将会看到如下的内容:

现在让我们通过文件浏览器来查看真实的效果。

新文件夹已经被写入到了本地的文件系统中,正如预期那样。

创建一个文件并读/写它的内容

现在,让我们探索在文件系统中读写文件的能力。

await fs.writeFile("/foo/hello.txt", "Hello, World!", { root })
JavaScript
const content = await fs.readFileAsText("/foo/hello.txt", { root })
console.log(content)
JavaScript

我们将会在控制台中看到如下的输出:

我们也可以在文件浏览器中看到这个新文件:

最终结果

现在,让我们再次执行 readTree,我们将会看到如下的内容,以属性结构的形式显示出 root 目录下所有的条目。

console.log(await fs.readTree("/", { root }))
JavaScript

就是这样,在浏览器中管理文件和在 Node.js 中一样简单(实际上更简单,因为这个 fs 模块提供了比 Node.js 更多的便捷函数)。

请自行查看 @ayonli/jsext/fs 模块以了解更多它的功能,或者探索 @ayonli/jsext 扩展库以了解更多它的特性。

Comments

Leave a comment