在早期我们经常听到这样的说法:浏览器是一个沙盒,它不允许我们操作本地文件,但是现在这个说法已经不再适用了,因为我们可以使用 File System Access api 来实现这个功能。
File System Access API 是一项 Web API,允许 Web 应用程序从用户设备的本地文件系统中读取和写入文件。
它提供了一种简单且安全的方法,让用户在不离开 Web 应用的情况下,从本地文件系统中操作文件。
这项 API 为 Web 应用程序提供了更多的灵活性和功能,使其更接近于本地应用程序的体验。
File System Access API 遵循同源策略,只允许 Web 应用程序在具有相同源的文件系统上进行操作。
当用户使用该 API 时,会提示用户授权应用程序访问他们的文件系统。
如果用户授权,则应用程序可以使用该 API 访问用户选择的文件和目录。
使用 File System Access API 可以访问本地文件系统,从而实现一些有用的功能,例如:
我不是很喜欢概念性的东西,上面的内容是网上借鉴的(文化人),我更喜欢直接上代码,所以我们直接上代码。
首先我们来看看如何选择文件,这个功能是 File System Access API 中最基础的功能,我们可以通过 showOpenFilePicker 方法来实现。
const fileHandle = await window.showOpenFilePicker();
console.log(fileHandle);
可以看到我们这里使用了async/await语法,这是因为showOpenFilePicker异步方法,它会返回一个Promise对象,我们可以通过await来等待它的结果。
showOpenFilePicker方法会返回一个FileHandle对象,我们可以通过它来获取文件的信息。
我们来看看它最后返回的结果:
可以看到的是最后的结果是一个数组,这是因为我们可以选择多个文件;
而这个数组的每一项都是一个FileSystemFileHandle对象,我们可以通过它来获取和操作文件。
FileSystemFileHandle对象是一个代表文件的对象,它提供了一些方法来获取和操作文件。
FileSystemFileHandle提供了一些方法来获取和操作文件,例如:
我们来看看如何使用getFile方法来获取文件。
const fileHandle = await window.showOpenFilePicker();
const file = await fileHandle[0].getFile();
console.log(file);
可以看到,我们通过getFile方法获取到了文件,它返回的是一个File对象,我们可以通过它来获取文件的信息。
都拿到File对象了,后面怎么操作就很熟悉了吧,直接使用FileReader对象来获取文件内容,后面你爱怎么操作就怎么操作。
通过截图我们还看到了有kind属性和name属性,这两个属性是继承自FileSystemHandle对象的。
FileSystemFileHandle继承自FileSystemHandle,它是一个代表文件系统中的文件或目录的对象。
FileSystemHandle提供了一些方法来获取和操作文件系统中的文件或目录,例如:
我们可以通过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);
可以看到,我们通过showDirectoryPicker方法获取到了目录,它返回的是一个FileSystemDirectoryHandle对象,我们可以通过它来获取和操作目录。
使用showDirectoryPicker方法时,浏览器会提示用户授权应用程序访问他们的文件系统,请不要拒绝哟。
FileSystemDirectoryHandle对象是一个代表文件系统中的目录的对象,它提供了一些方法来获取和操作目录。
FileSystemDirectoryHandle提供的方法就比较多了,例如:
entries、keys、values这三个方法都是用来获取目录中的所有文件和目录的,它们返回的都是一个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对象是文件还是目录。
而这里的getFileHandle、getDirectoryHandle就是用来获取目录中的文件和目录的,它们都返回一个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还有其他的属性,例如:
写入文件可以使用上面提到的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方法接收两个参数:
目前只有create一个选项,如果设置为true,则会创建一个目录,如果设置为false,则会获取一个目录。
如果目录不存在,且create为false,则会报错。
删除目录可以使用FileSystemDirectoryHandle对象的removeEntry方法来删除一个目录。
const directoryHandle = await window.showDirectoryPicker();
await directoryHandle.removeEntry('new-directory');
removeEntry方法接收一个参数,一个字符串,用于指定要删除的目录的名称。
截止到现在,showDirectoryPicker和showOpenFilePicker这两个方法在Chrome 86版本中已经可以正常使用了,但是在Firefox中还不支持。
下面是来自caniuse的兼容性数据:
虽然Firefox还不支持,但是在一些实验性的项目上我们可以使用这些API,指定用户使用Chrome浏览器来访问。
本文主要介绍了File System Access API的基本使用,包括如何获取文件和目录,以及如何操作文件和目录。
同时因为有这个API有跨域的问题,所以这次就没办法给大家演示码上掘金的代码了,感兴趣的同学可以将我文中的代码动手尝试一下。
作者:田八
链接:https://juejin.cn/post/7203701875530039357
PC端上传文件多半用插件,引入flash都没关系,但是移动端要是还用各种冗余的插件估计得被喷死,项目里面需要做图片上传的功能,既然H5已经有相关的接口且兼容性良好,当然优先考虑用H5来实现。
首先我们定义一个input标签type=file、然后我们定义一个jsReadFiles的方法将文件作为参数;当上传文件的时候读取这个文件。图片上传成功,只是图片路径变成了base64编码的形式。
HTML5读取文件主要利用的就是FileReader这个API,它的使用需要从一个构造函数开始,保存文件的关键是生成文件对象,可以使用URL.createObjectURL()方法实现,该方法能返回给定对象的URL,用在<a>标签的href属性上就可以创建可下载的文件链接。
在JavaScript文件中存储敏感数据,不仅是一种错误的实践方式,而且还是一种非常危险的行为,长期以来大家都知道这一点。
比如我写了一个JS文件,这个文件需要调用另外一个JS文件,该如何实现呢?这篇文章主要介绍:在js文件中引入另一个js文件的实现
最近有这样一个需求,就是在HTML页面中有个按钮导出,点击它,将构造一个文档并存储到本地文件系统中。另外还有个按钮,点击它,从本地文件系统中读取一个文件并对内容进行分析。
从 Yarn 横空出世推出 lock 文件以来,已经两年多时间了,npm 也在 5.0 版本加入了类似的功能,lock 文件越来越被开发者们接收和认可。本篇文章想从前端视角探讨一下我们为什么需要 lock 文件,以及它的一些成本与风险,当然其中一些观点对于后端也是适用的
什么是断点续传?就是下载文件时,不必重头开始下载,而是从指定的位置继续下载,这样的功能就叫做断点续传。前端通过FileList对象获取到相应的文件,按照指定的分割方式将大文件分段,然后一段一段地传给后端,后端再按顺序一段段将文件进行拼接。
form表单的enctype属性:规定了form表单数据在发送到服务器时候的编码方式.。application/x-www-form-urlencoded:默认编码方式,multipart/form-data:指定传输数据为二进制数据,例如图片、mp3、文件,text/plain:纯文本的传输。空格转换为“+”,但不支持特殊字符编码。
适用场景: 网络绝对路径的URL文件或图片,不存储到本地,转换成stream,直接使用HTTPClient传送到SpringBoot的服务端,将文件存储下来,并返回一个文件地址。目前分层架构的系统越来越多这种需求,所以记录下来以备不时之需。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!