网站访问用户文件夹
网页端可通过 File System Access API 访问用户本地文件夹。
JS 读取文件夹内全部文件
JS 读取文件夹选择文件夹 API
通过 showDirectoryPicker API 打开选择文件夹对话框,选择后需用户确认权限方可生效。代码如下:
btn.onclick = function () {
console.log('click me')
showDirectoryPicker()
}JS 读取文件夹得到文件与子文件夹
showDirectoryPicker API 的返回值就是得到的文件或文件夹的句柄,返回如下:
{
kind: 'directory',
name:'xxx'
}其中,kind 表示得到的类型,directory 表示文件夹,file 表示文件。name 为该文件夹或文件的名称。
获取可能失败,用户可能拒绝访问,用 try...catch 捕获错误。
拿到了文件夹时,可通过 .entries() 方法获取文件夹内所有内容,返回值是异步迭代器,通过 for await of 循环拿到子文件句柄。句柄返回内容如下:
;([
'folder-request',
{
kind: 'directory',
name: 'folder-request',
},
],
[
'demo.html',
{
kind: 'file',
name: 'demo.html',
},
])由此可拿到文件夹或文件,通过递归遍历获取句柄,直到全部为文件。代码如下:
查看代码
btn.onclick = async function () {
try {
const handle = await showDirectoryPicker()
const root = await processHandle(handle)
} catch (err) {
// ...
}
}
async function processHandle(handle) {
// 添加判断,终止递归,返回文件
if (handle.kind === 'file') {
return handle
}
handle.children = []
const iter = await handle.entries() // 获取文件夹中所有内容
for await (const info of iter) {
const subHandle = await processHandle(info[1]) // 返回的是一个数组,返回的内容格式如上所述。通过递归的思想一直获取文件夹内的内容
handle.children.push(subHandle)
}
return handle
}现在 root 能够拿到一个树状结构的句柄。
JS 读取文件夹读取文件
通过 getFile() 可以获取文件内容,使用 FileReader() 类中的 readAsText 方法就能读取文件内容,该读取操作是异步操作,通过 onload 函数能够最终获取结果。代码如下:
btn.onclick = async function () {
try {
const handle = await showDirectoryPicker()
const root = await processHandle(handle)
// 获取内容
const file = await root.children[1].getFile()
const reader = new FileReader()
reader.onload = (e) => {
console.log(e.target.result)
}
} catch (err) {
// ...
}
}
// ...JS 文件夹其他操作
JS 文件夹多选
要从多个文件中读取,传入 options 对象给 showOpenFilePicker(),默认 multiple 为 false,多选需设为 true。
let fileHandles
const options = { multiple: true }
const pickFile = async () => {
fileHandles = await window.showOpenFilePicker(options)
}其他选项可用于指示可以选择的文件类型。例如,只想接收 .png 文件,选项对象将包括以下内容
const options = {
types: [
{
description: 'Images',
accept: { 'image/png': '.png' },
},
],
excludeAcceptAllOption: true,
}多选后返回的结果是一个包含多个文件的数组,因此获取它们的内容将通过以下方式完成:
const pickFile = async () => {
const fileList = await window.showOpenFilePicker({ multiple: true })
const allContent = await Promise.all(
fileList.map(async (fileItem) => {
const file = await fileItem.getFile()
const content = await file.text()
return content
}),
)
console.log(allContent)
}JS 文件夹写文件
写文件的操作分为以下几步:
- 通过
createWritable()返回一个FileSystemWritableFileStream对象 - 调用
write()将需要传递内容写入此流 - 调用
close()关闭流
btn.onclick = async function () {
try {
const handle = await showDirectoryPicker({
types: [
{
description: 'Test files',
accept: {
'text/plain': ['.txt'],
},
},
],
})
// 写文件
const writable = await handle.createWritable()
await writable.write('hello world')
await writable.close()
} catch (err) {
// ...
}
}这样就能写一个 html 内容。
JS 文件夹编辑文件内容
编辑文件的本质是先通过 showOpenFilePicker() 和 getFile() 方法读取文件,然后使用createWritable() , write() 并 close() 写入同一个文件内,实现编辑操作。
let fileHandle
const writeFile = async () => {
;[fileHandle] = await window.showOpenFilePicker()
const file = await fileHandle.getFile()
const writable = await fileHandle.createWritable()
await writable.write('这是新写入的内容')
await writable.close()
}JS 文件夹删除文件
调用 remove() 方法可以删除全部文件或文件夹;传入对应文件名称可以指定删除的文件或文件夹。
const removeDirectory = async () => {
const directoryHandle = await window.showDirectoryPicker()
await directoryHandle.remove()
}
// 删除选定文件夹中名为data.txt的单个文件
const removeSelfFile = async () => {
const directoryHandle = await window.showDirectoryPicker()
await directoryHandle.removeEntry('data.txt')
}
// 递归删除名为“data”的文件夹
const removeAllDirectory = async () => {
const directoryHandle = await window.showDirectoryPicker()
await directoryHandle.removeEntry('data', { recursive: true })
}