文件操作利器:showOpenFilePicker

概述

在传统的前端开发中,处理用户文件一直是个棘手的问题。虽然 <input type="file"> 提供了基本的文件选择功能,但当需要处理整个目录结构时,开发者往往需要借助复杂的后端支持或Electron等桌面框架。showDirectoryPicker() 的出现彻底改变了这一局面,它为Web应用提供了原生的目录访问能力,文件操作体验。

showDirectoryPicker

showDirectoryPicker() 是 File System Access API 的核心方法之一,它允许Web应用通过用户授权的方式访问整个目录结构,而不仅仅是单个文件。这意味着开发者现在可以在浏览器中实现以前只能在桌面应用中才能完成的文件操作。

核心特性

  • 完整的目录访问:读取、遍历、修改目录内容
  • 权限持久化:用户授权后可保存访问权限
  • 安全沙箱:在严格的用户控制下运行
  • 现代化API:基于Promise的异步设计

浏览器支持情况

只有部分浏览器支持,并且版本比较新,希望以后能够更好支持

基础使用与语法

基本调用方式

js 复制代码
async function selectDirectory() {
  try {
    const directoryHandle = await window.showDirectoryPicker();
    console.log('选择的目录:', directoryHandle.name);
    return directoryHandle;
  } catch (err) {
    if (err.name === 'AbortError') {
      console.log('用户取消了选择');
    } else {
      console.error('发生错误:', err);
    }
  }
}

配置选项

js 复制代码
const options = {
  id: 'projectFolder', // 标识符,用于记住用户选择
  mode: 'readwrite',   // 权限模式:read 或 readwrite
  startIn: 'documents' // 起始目录:desktop, documents, downloads等
};

const directoryHandle = await showDirectoryPicker(options);

权限模式

  • read :仅读取权限,可以列出文件和读取内容
  • readwrite :读写权限,可以创建、修改、删除文件

实际应用场景

遍历文件内容

js 复制代码
async function* walkDirectory(directoryHandle, path = '') {
  for await (const entry of directoryHandle.values()) {
    const entryPath = `${path}/${entry.name}`;
    
    if (entry.kind === 'directory') {
      yield* await walkDirectory(entry, entryPath);
    } else {
      yield {
        handle: entry,
        path: entryPath,
        kind: 'file'
      };
    }
  }
}

// 使用示例
async function printDirectoryTree() {
  const directoryHandle = await showDirectoryPicker();
  
  for await (const entry of walkDirectory(directoryHandle)) {
    console.log(entry.path);
  }
}

printDirectoryTree()

解析本地文件夹可视化到线上

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <button>打开文件</button>


    <script>

        const btn = document.querySelector('button');

        btn.addEventListener('click', async () => {
            const fileHandles = await showDirectoryPicker();

            await processHandle(fileHandles);


            console.log("fileHandles----", fileHandles);

            processFile(fileHandles);

            async function processHandle(handle) {
                if (handle.kind === 'file') {
                    return
                }
                const iter = handle.entries();
                handle.children = []
                for await (const [name, childHandle] of iter) {
                    handle.children.push(childHandle);
                    processHandle(childHandle);
                }
            }



            async function processFile(fileHandles) {

                if (fileHandles.kind === 'file') {
                    const file = await fileHandles.getFile();
                    console.log("file----", file);
                    const fileReader = new FileReader();

                    fileReader.onload = (e) => {
                        console.log("fileReader.result---", e.target.result);
                    }

                    fileReader.readAsText(file);
                } else {
                    for (let i = 0; i < fileHandles.children.length; i++) {
                        const childHandle = fileHandles.children[i];
                        processFile(childHandle);
                    }
                }


            }
        });
    </script>
</body>

</html>
相关推荐
Huanzhi_Lin3 分钟前
Nginx本地资源服务器-常用脚本
服务器·前端·nginx·batch·静态资源服务器
weixin199701080164 分钟前
《好看视频商品详情页前端性能优化实战》
前端·性能优化·音视频
有意义5 分钟前
深入理解浏览器存储方案:从Cookie到JWT登录认证
前端·面试·浏览器
jiayong235 分钟前
第 6 课:第二轮真实重构,拆出任务表格组件
前端·重构
jiayong2312 分钟前
第 4 课:怎么把一个大页面拆成多个组件
运维·服务器·前端
skywalk816315 分钟前
使用DuMate帮助创建 Python 3.9 环境并部署 Kotti CMS
前端·chrome
英俊潇洒美少年18 分钟前
Vue Hook 与 React Hook 全面解析:区别、用法、实战及避坑指南
前端·vue.js·react.js
吴声子夜歌24 分钟前
ES6——Symbol详解
开发语言·javascript·es6
weixin_7042660526 分钟前
项目总结一
java·前端·spring boot·后端·spring