服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

使用File System Access API让浏览器拥有操作本地文件的能力

日期: 来源:三分钟学前端收集编辑:田八

在早期我们经常听到这样的说法:浏览器是一个沙盒,它不允许我们操作本地文件,但是现在这个说法已经不再适用了,因为我们可以使用 File System Access API 来实现这个功能。

什么是 File System Access API

File System Access API 是一项 Web API,允许 Web 应用程序从用户设备的本地文件系统中读取和写入文件。

它提供了一种简单且安全的方法,让用户在不离开 Web 应用的情况下,从本地文件系统中操作文件。

这项 APIWeb 应用程序提供了更多的灵活性和功能,使其更接近于本地应用程序的体验。

File System Access API 遵循同源策略,只允许 Web 应用程序在具有相同源的文件系统上进行操作。

当用户使用该 API 时,会提示用户授权应用程序访问他们的文件系统。

如果用户授权,则应用程序可以使用该 API 访问用户选择的文件和目录。

使用 File System Access API 可以访问本地文件系统,从而实现一些有用的功能,例如:

  • 将文件从本地文件系统上传到 Web 应用程序;
  • Web 应用程序中的数据写入到本地文件系统中;
  • 在用户的本地文件系统上创建、重命名和删除文件;
  • 读取本地文件系统上的文件内容。

如何使用 File System Access API

我不是很喜欢概念性的东西,上面的内容是网上借鉴的(文化人),我更喜欢直接上代码,所以我们直接上代码。

选择文件

首先我们来看看如何选择文件,这个功能是 File System Access API 中最基础的功能,我们可以通过 showOpenFilePicker 方法来实现。

const fileHandle = await window.showOpenFilePicker();
console.log(fileHandle);
复制代码

可以看到我们这里使用了async/await语法,这是因为showOpenFilePicker异步方法,它会返回一个Promise对象,我们可以通过await来等待它的结果。

showOpenFilePicker方法会返回一个FileHandle对象,我们可以通过它来获取文件的信息。

我们来看看它最后返回的结果:

image.png

可以看到的是最后的结果是一个数组,这是因为我们可以选择多个文件;

而这个数组的每一项都是一个FileSystemFileHandle对象,我们可以通过它来获取和操作文件。

FileSystemFileHandle

FileSystemFileHandle对象是一个代表文件的对象,它提供了一些方法来获取和操作文件。

FileSystemFileHandle提供了一些方法来获取和操作文件,例如:

  • getFile:返回一个Promise对象,用于获取文件;
  • createSyncAccessHandle:返回一个FileSystemSyncAccessHandle对象,用于同步访问文件;
  • createWritable:返回一个Promise对象,用于创建一个可写流,用于写入文件;

我们来看看如何使用getFile方法来获取文件。

const fileHandle = await window.showOpenFilePicker();
const file = await fileHandle[0].getFile();
console.log(file);
复制代码
image.png

可以看到,我们通过getFile方法获取到了文件,它返回的是一个File对象,我们可以通过它来获取文件的信息。

都拿到File对象了,后面怎么操作就很熟悉了吧,直接使用FileReader对象来获取文件内容,后面你爱怎么操作就怎么操作。

FileSystemHandle

通过截图我们还看到了有kind属性和name属性,这两个属性是继承自FileSystemHandle对象的。

FileSystemFileHandle继承自FileSystemHandle,它是一个代表文件系统中的文件或目录的对象。

FileSystemHandle提供了一些方法来获取和操作文件系统中的文件或目录,例如:

  • kind:返回一个字符串,用于表示文件或目录;
  • name:返回一个字符串,用于表示文件或目录的名称;
  • isSameEntry:返回一个boolean值,用于表示两个文件或目录是否相同;
  • queryPermission:返回一个Promise对象,用于查询文件或目录的权限;
  • requestPermission:返回一个Promise对象,用于请求文件或目录的权限;
  • remove:返回一个Promise对象,用于删除文件或目录;

我们可以通过kind属性来判断当前的FileSystemHandle对象是文件还是目录。

const fileHandle = await window.showOpenFilePicker();
const file = await fileHandle[0].getFile();
console.log(fileHandle[0].kind);
复制代码

当然我们使用的是showOpenFilePicker方法,所以它返回的肯定是文件,所以还有一个showDirectoryPicker方法,它可以用来选择目录。

选择目录

选择目录的方法和选择文件的方法是一样的,只是我们需要使用showDirectoryPicker方法。

const directoryHandle = await window.showDirectoryPicker();
console.log(directoryHandle);
复制代码
image.png

可以看到,我们通过showDirectoryPicker方法获取到了目录,它返回的是一个FileSystemDirectoryHandle对象,我们可以通过它来获取和操作目录。

使用showDirectoryPicker方法时,浏览器会提示用户授权应用程序访问他们的文件系统,请不要拒绝哟。

FileSystemDirectoryHandle

FileSystemDirectoryHandle对象是一个代表文件系统中的目录的对象,它提供了一些方法来获取和操作目录。

FileSystemDirectoryHandle提供的方法就比较多了,例如:

  • entries:返回一个AsyncIterable对象,用于获取目录中的所有文件和目录;
  • keys:返回一个AsyncIterable对象,用于获取目录中的所有文件和目录的名称;
  • values:返回一个AsyncIterable对象,用于获取目录中的所有文件和目录的FileSystemHandle对象;
  • getFileHandle:返回一个Promise对象,用于获取目录中的文件;
  • getDirectoryHandle:返回一个Promise对象,用于获取目录中的目录;
  • removeEntry:返回一个Promise对象,用于删除目录中的文件或目录;
  • resolve:返回一个Promise对象,用于获取目录中的文件或目录;

entrieskeysvalues这三个方法都是用来获取目录中的所有文件和目录的,它们返回的都是一个AsyncIterable对象,我们可以通过for await...of语法来遍历它。

const directoryHandle = await window.showDirectoryPicker();
for await (const [name, handle] of directoryHandle.entries()) {
    if (handle.kind === 'file') {
        console.log(name, 'file');
    } else {
        console.log(name, 'directory');
    }
}
复制代码

我们可以通过handle.kind来判断当前的FileSystemHandle对象是文件还是目录。

而这里的getFileHandlegetDirectoryHandle就是用来获取目录中的文件和目录的,它们都返回一个Promise对象,我们可以通过await来获取它们。

const directoryHandle = await window.showDirectoryPicker();
for await (const [name, handle] of directoryHandle.entries()) {
    if (handle.kind === 'file') {
        const fileHandle = await directoryHandle.getFileHandle(name);
        console.log(fileHandle);
    } else {
        const directoryHandle = await directoryHandle.getDirectoryHandle(name);
        console.log(directoryHandle);
    }
}
复制代码

这里大家可以自己尝试一下,我就不截图了。

操作文件

上面我们了解到了如何获取文件和目录,那么我们接下来就来看看如何操作文件和目录。

读取文件

读取文件做过文件上传的同学应该都很熟悉了,我们可以使用FileReader对象来读取文件。

const fileHandle = await window.showOpenFilePicker({
    excludeAcceptAllOption: false,
    types: [
        {
            description: 'Text files',
            accept: {
                'text/plain': ['.txt'],
            },
        },
    ],
});
const file = await fileHandle[0].getFile();
const reader = new FileReader();
reader.onload = () => {
    console.log(reader.result);
};
reader.readAsText(file);
复制代码

这里我们在使用showOpenFilePicker方法时,我们通过types属性来限制文件的类型,这样用户就只能选择文本文件了。

showOpenFilePicker还有其他的属性,例如:

  • multiple:一个boolean值,默认为false,是否允许用户选择多个文件;
  • excludeAcceptAllOption:一个boolean值,默认为false,是否允许用户选择所有类型的文件(就是选择文件下拉的所有文件选项);
  • types:一个数组,用于限制用户选择的文件类型(就是选择文件的下拉选项);
    • description:一个字符串,用于描述文件类型(就是下拉选项的文字);
    • accept:一个对象,用于描述文件类型(就是控制选择文件的类型,例如image/*表示图片类型),具体可以参考:MIME types[1]

写入文件

写入文件可以使用上面提到的FileSystemFileHandle对象的createWritable方法来创建一个FileSystemWritableFileStream对象,然后通过它来写入文件。

const fileHandle = await window.showSaveFilePicker({
    types: [
        {
            description: 'Text files',
            accept: {
                'text/plain': ['.txt'],
            },
        },
    ],
});

// 创建一个可写流
const writable = await fileHandle.createWritable();

// 写入数据
await writable.write('Hello World!');

// 关闭流
await writable.close();
复制代码

这里我们使用showSaveFilePicker方法来创建一个文件,然后通过createWritable方法来创建一个可写流,然后通过write方法来写入数据,最后通过close方法来关闭流。

showSaveFilePicker也是文件选择器的一种,它和showOpenFilePicker的区别在于,showSaveFilePicker是用来创建文件的,而showOpenFilePicker是用来选择文件的。

showSaveFilePicker返回的是新创建的文件的FileSystemFileHandle对象,而showOpenFilePicker返回的是选择的文件的FileSystemFileHandle对象。

注意:操作文件流时,一定要记得关闭流哟,否则会导致文件锁定,无法进行其他操作,做前端的同学可能对这一块并不熟悉,所以特此提醒一下。

操作目录

上面我们已经知道了如何操作文件了,那么接下来我们就来看看如何操作目录。

创建目录

创建目录可以使用FileSystemDirectoryHandle对象的getDirectoryHandle方法来创建一个目录。

const directoryHandle = await window.showDirectoryPicker();
const newDirectoryHandle = await directoryHandle.getDirectoryHandle('new-directory', {
    create: true,
});
复制代码

getDirectoryHandle方法接收两个参数:

  • name:一个字符串,用于指定目录的名称;
  • options:一个对象,用于指定目录的选项(可选);
    • create:一个boolean值,默认为false,是否创建目录;

目前只有create一个选项,如果设置为true,则会创建一个目录,如果设置为false,则会获取一个目录。

如果目录不存在,且createfalse,则会报错。

删除目录

删除目录可以使用FileSystemDirectoryHandle对象的removeEntry方法来删除一个目录。

const directoryHandle = await window.showDirectoryPicker();
await directoryHandle.removeEntry('new-directory');
复制代码

removeEntry方法接收一个参数,一个字符串,用于指定要删除的目录的名称。

兼容性

截止到现在,showDirectoryPickershowOpenFilePicker这两个方法在Chrome 86版本中已经可以正常使用了,但是在Firefox中还不支持。

下面是来自caniuse[2]的兼容性数据:

image.png

虽然Firefox还不支持,但是在一些实验性的项目上我们可以使用这些API,指定用户使用Chrome浏览器来访问。

总结

本文主要介绍了File System Access API的基本使用,包括如何获取文件和目录,以及如何操作文件和目录。

同时因为有这个API有跨域的问题,所以这次就没办法给大家演示码上掘金的代码了,感兴趣的同学可以将我文中的代码动手尝试一下。

可以发现我这次讲解的并不是很详细,因为这个API还在实验阶段,所以我只是简单的介绍了一下,如果大家想要了解更多的话,可以参考下面的参考资料。

关于本文

作者:田八

https://juejin.cn/post/7203701875530039357

最后


欢迎关注「三分钟学前端」
号内回复:
「网络」,自动获取三分钟学前端网络篇小书(90+页)
「JS」,自动获取三分钟学前端 JS 篇小书(120+页)
「算法」,自动获取 github 2.9k+ 的前端算法小书
「面试」,自动获取 github 23.2k+ 的前端面试小书
「简历」,自动获取程序员系列的 120 套模版
》》面试官也在看的前端面试资料《《
“在看和转发”就是最大的支持


相关阅读

  • Hey!两会丨霄霄访豫记① “想把公司开回家”

  • 3月的北京,春风拂面,生机勃勃。在全国两会的会场外,我们要去拜访一些优秀的河南老乡,和他们聊聊家乡的故事。  今天要见的老乡,名叫范学鹏。近年来,老家河南大力推进科技创新和
  • 事关物价、消费、GDP……国家发改委最新回应!

  • 3月6日,国务院新闻办公室举行“权威部门话开局”系列主题新闻发布会,介绍“着力推动高质量发展,为全面建设社会主义现代化国家开好局起好步”,并答记者问。5%左右的预期目标符合
  • 主动投案 江西一设区市中院原副院长被查

  • 鹰潭市中级人民法院原副院长王建东涉嫌严重违纪违法,主动投案,目前正接受鹰潭市纪委市监委纪律审查和监察调查。王建东简历王建东,男,汉族,1961年1月出生,吉林大安人,在职大学学历,1

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • Vue2与Vue3响应式原理与依赖收集详解

  • 前言继 Angular 和 React 之后,尤大在 2016 年发布了如今“前端三剑客”之一的 Vue 2.0,并凭借其简单易用、轻量高效的特点受到了广泛的欢迎,特别是在国内环境中。然而 Vue 2
  • 论线下机构跑路的必然性

  • 持续力公众号ID:scalerstalk个人微信号:fscalers (可加Scalers个人微信交流)关注ScalersTalk 成长会 2023年开放报名,参见《大量读写,持续改变——S成长会2023报名启动》。最近