showDirectoryPicker浏览器读取文件/文件夹目录

1,522 阅读3分钟

文章背景

之前公司有一个需要读取本地文件视频的需求,但是在我们最初学习js的时候,老师讲的是无法读取文件夹,这里有个误区,技术是一直在迭代,好吧,是我out了。然后我直接告诉产品这个需求无法实现,最终解决的方案是后端的兄弟采用Go写的一个本地服务器来读取的。后来偶然在网上发现了vscode居然有个网页编辑器,这个就打开我的新世界了,既然有网页版的编辑器,那么必然需要读取本地的文件,经过我了解,现代的浏览器确实可以实现,但是目前还会有一些兼容性的问题有待提升,话不多说,往下看!!

本章需要了解的技术点

// 文档地址:https://developer.mozilla.org/zh-CN/
window.showDirectoryPicker() // 用于显示一个目录选择器,以允许用户选择一个目录。
Object.entries() // 静态方法返回一个数组,包含给定对象自有的可枚举字符串键属性的键值对。
// const obj = { foo: "bar", baz: 42 };
// console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
for await...of // 异步迭代器

showDirectoryPickerAPI有兼容要求,如果当前开发的浏览器不支持,建议查询其他解决方案,感兴趣的也看看

image.png

实现

<button id="btn">文件夹读取</button>
const btn = document.getElementById("btn");
btn.addEventListener("click", async function (e) {
    const handle = await window.showDirectoryPicker();
    console.log(handle);
});

通过showDirectoryPickerAPi可以得到一个文件目录,包含名称、文件/文件夹类型,注意方法是异步的,得到一个FileSystemDirectoryHandle处理器

Snipaste_2024-09-06_09-29-06.png

此时我们采用异步迭代器对目录进行处理,得到一个类似Map对象的键值对

<button id="btn">文件夹读取</button>
const btn = document.getElementById("btn");
btn.addEventListener("click", async function (e) {
    const handle = await window.showDirectoryPicker();
    const ent = await handle.entries(); 
    for await (const item of ent) {
         console.log(item);
    }
});

Snipaste_2024-09-06_09-29-40.png Snipaste_2024-09-06_09-29-21.png

将目录处理成一个我们常见的树形数据

<button id="btn">文件夹读取</button>
const btn = document.getElementById("btn");
async function processHandle(handle) {
    if (handle.kind === "file") {
    // 如果是文件直接退出
        return;
    }
const ent = await handle.entries();
handle.children = [];
    for await (const item of ent) {
        handle.children.push(item[1]);
        processHandle(item[1]);
    }
}
btn.addEventListener("click", async function (e) {
    const handle = await window.showDirectoryPicker();
    await processHandle(handle);
});

读取文件内容信息,得到我们平时上传的文件对象,然后我们就可以直接读出

<button id="btn">文件夹读取</button>
const btn = document.getElementById("btn");
async function processHandle(handle) {
    if (handle.kind === "file") {
    // 如果是文件直接退出
        return;
    }
const ent = await handle.entries();
handle.children = [];
    for await (const item of ent) {
        handle.children.push(item[1]);
        processHandle(item[1]);
    }
}
btn.addEventListener("click", async function (e) {
    const handle = await window.showDirectoryPicker();
    await processHandle(handle);
    const file = await handle.children[5].getFile();
    const reader = new FileReader();
    reader.onload = (e) => {
         console.log(e.target.result);
    };
    console.log(reader.readAsText(file)); // 文件内容
});

image.png

结尾

东西都不是啥高级的东西,就是需要平时的积累,创新,本次过后我也认识到,技术在不断的迭代,如果不一直学习,将会差距越来越大,为什么会有35岁危机,个人认为有扎实的功底,不断创新的精神,和不断上进的决心,坚持,在各行各业都不大可能淘汰,企业差的永远是能解决问题的人才。最后祝愿各位兄弟姐妹都能一起在此行业一起走下去。

创作小白,第一次写文章,轻点喷,嘿嘿!代码如有不对,还请在评论区指出,与君共勉之!!!