
在体验 vscode 在线版时,发现在浏览器已经可以直接读写本地文件系统。查了一下发现是 File System Access API 提供了相关功能。
File System Access API 是一项 Web API,允许 Web 应用程序从用户设备的本地文件系统中读取和写入文件。
使用 File System Access API 可以访问本地文件系统,从而实现一些有用的功能,例如:
- 将文件从本地文件系统上传到 Web 应用程序;
- 将 Web 应用程序中的数据写入到本地文件系统中;
- 在用户的本地文件系统上创建、重命名和删除文件;
- 读取本地文件系统上的文件内容。
接口
FileSystemHandle
父 FileSystemHandle 类帮助定义两个子类:FileSystemFileHandle 和 FileSystemDirectoryHandle,分别用于文件和目录。
FileSystemFileHandle 操作文件
FileSystemFileHandle 对象是一个代表文件的对象,它提供了一些方法来获取和操作文件。例如:
实例方法
getFile 获取文件
createSyncAccessHandle
返回一个 FileSystemSyncAccessHandle 对象,用于同步访问文件;
createWritable 写入文件
返回一个Promise对象,用于创建一个可写流,用于写入文件;createWritable 方法会创建一个 FileSystemWritableFileStream 对象,然后通过它来写入文件。
// 创建一个可写流const writable = await fileHandle.createWritable();// 写入数据await writable.write('Hello World!');// 关闭流await writable.close();
:::info 注意:操作文件流完成时,一定要记得关闭流,否则会导致文件锁定,无法进行其他操作 :::
属性
kind 属性和 name 属性,这两个属性是继承自FileSystemHandle对象的。
kind 类型 文件或目录
返回一个字符串,用于表示文件或目录; ‘directory’ | ‘file’
这里在 FileSystemFileHandle 文件对象中都是 ‘file’
name 文件或目录的名称
返回一个字符串,用于表示文件或目录的名称;
FileSystemDirectoryHandle 操作目录
FileSystemDirectoryHandle 对象是一个代表文件系统中的目录的对象,它提供了一些方法来获取和操作目录。
实例方法
- entries:返回一个AsyncIterable对象,用于获取目录中的所有文件和目录;
- keys:返回一个AsyncIterable对象,用于获取目录中的所有文件和目录的名称;
- values:返回一个AsyncIterable对象,用于获取目录中的所有文件和目录的 FileSystemHandle 对象;
- getFileHandle:返回一个Promise对象,用于获取目录中的文件;
- getDirectoryHandle:返回一个Promise对象,用于获取目录中的目录;
- removeEntry:返回一个Promise对象,用于删除目录中的文件或目录;
- resolve:返回一个Promise对象,用于获取目录中的文件或目录;
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');}}
getFileHandle 、getDirectoryHandle
而这里的 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);}}
getDirectoryHandle 创建目录
创建目录可以使用 FileSystemDirectoryHandle 对象的 getDirectoryHandle 方法。
const directoryHandle = await window.showDirectoryPicker();const newDirectoryHandle = await directoryHandle.getDirect1oryHandle('new-directory', {create: true,});
getDirectoryHandle方法接收两个参数:
name:一个字符串,用于指定目录的名称;
options:一个对象,用于指定目录的选项(可选);
create:一个boolean值,默认为false,是否创建目录;
目前只有create一个选项,如果设置为true,则会创建一个目录,如果设置为false,则会获取一个目录。
如果目录不存在,且create为false,则会报错。
removeEntry 删除目录
删除目录可以使用FileSystemDirectoryHandle对象的removeEntry方法
onst directoryHandle = await window.showDirectoryPicker();await directoryHandle.removeEntry('new-directory');
removeEntry方法接收一个参数,一个字符串,用于指定要删除的目录的名称。
属性
kind 属性和 name 属性,这两个属性是继承自FileSystemHandle对象的。
kind 类型 文件或目录
返回一个字符串,用于表示文件或目录; ‘directory’ | ‘file’
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');}}
name 文件或目录的名称
FileSystemSyncAccessHandle
FileSystemWritableFileStream
方法
window.showOpenFilePicker() 选择文件
showOpenFilePicker 方法会打开文件选择器,用户选择文件后会返回一个包含 FileHandle 对象的数组,我们可以通过它来获取文件的信息。
如果用户在未进行选择的情况下关闭提示,或者所选文件被认为过于敏感或危险而无法暴露给网站,则会引发 AbortError。
options 参数可选
包含选项的对象,如下所示:
multiple 是否支持多选
是否多选,boolean。默认为false,是否允许用户选择多个文件
excludeAcceptAllOption 是否支持所有类型
一个boolean值,默认为false,是否允许用户选择所有类型的文件
types 允许的文件类型
description
accept
一个对象,用于描述文件类型(就是控制选择文件的类型,例如image/*表示图片类型),具体可以参考:MIME types
const fileHandle = await window.showOpenFilePicker({excludeAcceptAllOption: false,types: [{description: 'Text files',accept: {'text/plain': ['.txt'],},},],});
🙌🌰
showOpenFilePicker 是一个异步方法,它会返回一个 Promise 对象,我们可以通过 await 来等待它的结果。
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><button onclick="getFile()"> getFile </button><script>async function getFile() {const filePicked = await window.showOpenFilePicker();console.log("🚀 ~ file: index.html:17 ~ getFile ~ filePicked:", filePicked)const [fileHandle] = filePickedconsole.log("🚀 ~ file: index.html:18 ~ getFile ~ fileHandle:", fileHandle)const file = await fileHandle.getFile();console.log("🚀 ~ file: index.html:19 ~ getFile ~ file:", file)return file;}</script></body></html>
打印看看 showOpenFilePicker 最后返回的结果:
可以看到返回的结果是一个数组,这是因为我们可以选择多个文件;而这个数组的每一项都是一个FileSystemFileHandle 对象,我们可以通过它来获取和操作文件
window.showSaveFilePicker() 创建文件
showSaveFilePicker 也是文件选择器的一种,它和 showOpenFilePicker 的区别在于,showSaveFilePicker 是用来创建文件的,而 showOpenFilePicker 是用来选择文件的。
showSaveFilePicker 返回的是新创建的文件的 FileSystemFileHandle 对象,而 showOpenFilePicker 返回的是选择的文件的 FileSystemFileHandle 对象数组。
options 参数可选
excludeAcceptAllOption 是否支持所有类型
一个boolean值,默认为false,是否允许用户创建所有类型的文件
suggestedName 推荐名称
types 允许的文件类型
与 showOpenFilePicker 中的相同。
🙌🌰
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><button onclick="saveFile()"> saveFile </button><script>async function saveFile() {const fileHandle = await window.showSaveFilePicker({types: [{description: 'Text files',accept: {'text/plain': ['.txt'],},},],})console.log("🚀 ~ file: index.html:26 ~ saveFile ~ fileHandle:", fileHandle)// 创建一个可写流const writable = await fileHandle.createWritable();// 写入数据await writable.write('Hello World!');// 关闭流await writable.close();}</script></body></html>
window.showDirectoryFilePicker() 选择目录
showDirectoryFilePicker 方法会打开目录选择器,用户选择目录后返回 FileSystemDirectoryHandle 对象,我们可以通过它来获取目录的信息。
如果用户在未进行选择的情况下关闭提示,或者所选文件被认为过于敏感或危险而无法暴露给网站,则会引发 AbortError。
options 参数可选
包含选项的对象,如下所示:
id
通过指定 ID,浏览器可以记住不同 ID 的不同目录。如果对另一个选取器使用相同的 ID,则该选取器将在同一目录中打开。
mode
一个字符串,默认为只读访问,或是对目录的读写访问。”read” “readwrite”
startIn
🙌🌰
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><button onclick="getDirectory()"> getDirectory </button><script>async function getDirectory() {const directoryHandle = await window.showDirectoryPicker()console.log("🚀 ~ file: index.html:17 ~ getDirectory ~ directoryHandle:", directoryPicked)}</script></body></html>
打印看看 showDirectoryPicker 最后返回的结果:
可以看到,我们通过showDirectoryPicker方法获取到了目录,它返回的是一个FileSystemDirectoryHandle对象
使用 showDirectoryPicker 方法,浏览器会提示用户授权应用程序访问他们的文件系统,不要拒绝
