最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

前端JavaScript獲取本地文件目錄內(nèi)容的兩種實(shí)現(xiàn)方案

 更新時(shí)間:2025年08月26日 09:56:51   作者:頁面仔D  
由于瀏覽器的沙箱安全機(jī)制,前端 JavaScript 無法直接訪問本地文件系統(tǒng),必須通過用戶主動(dòng)授權(quán)(如選擇目錄操作)才能獲取文件目錄內(nèi)容,所以本文詳細(xì)介紹兩種方案的實(shí)現(xiàn)流程、代碼示例及適用場景,需要的朋友可以參考下

一、核心原理說明

由于瀏覽器的 “沙箱安全機(jī)制”,前端 JavaScript 無法直接訪問本地文件系統(tǒng),必須通過用戶主動(dòng)授權(quán)(如選擇目錄操作)才能獲取文件目錄內(nèi)容。目前主流實(shí)現(xiàn)方案基于兩種 API:傳統(tǒng) File API(兼容性優(yōu)先)和現(xiàn)代 FileSystem Access API(功能優(yōu)先),以下將詳細(xì)介紹兩種方案的實(shí)現(xiàn)流程、代碼示例及適用場景。

二、方案一:基于 File API 實(shí)現(xiàn)(兼容性首選)

1. 方案概述

通過隱藏的 <input type="file"> 標(biāo)簽(配置 webkitdirectorydirectory 屬性)觸發(fā)用戶選擇目錄操作,用戶選擇后通過 files 屬性獲取目錄下所有文件的元數(shù)據(jù)(如文件名、大小、相對路徑等)。該方案兼容幾乎所有現(xiàn)代瀏覽器(包括 Chrome、Firefox、Safari 等),但僅支持 “一次性獲取選中目錄內(nèi)容”,無法遞歸遍歷子目錄或修改文件。

2. 完整使用示例

2.1 HTML 結(jié)構(gòu)(含 UI 交互區(qū))

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>File API 目錄訪問示例</title>
    <!-- 引入 Tailwind 簡化樣式(也可自定義 CSS) -->
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        .file-item { display: flex; align-items: center; padding: 8px; border-bottom: 1px solid #eee; }
        .file-icon { margin-right: 8px; font-size: 18px; }
        .file-info { flex: 1; }
        .file-size { color: #666; font-size: 14px; }
    </style>
</head>
<body class="p-8 bg-gray-50">
    <div class="max-w-4xl mx-auto bg-white p-6 rounded-lg shadow">
        <h2 class="text-2xl font-bold mb-4">File API 目錄內(nèi)容獲取</h2>
        <!-- 觸發(fā)按鈕(隱藏原生 input) -->
        <button id="selectDirBtn" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
            選擇本地目錄
        </button>
        <input type="file" id="dirInput" webkitdirectory directory style="display: none;">
        
        <!-- 文件列表展示區(qū) -->
        <div class="mt-4 border rounded-lg max-h-80 overflow-y-auto">
            <div id="fileList" class="p-4 text-center text-gray-500">
                請選擇目錄以查看文件列表
            </div>
        </div>
    </div>

    <script>
        // 2.2 JavaScript 邏輯實(shí)現(xiàn)
        const dirInput = document.getElementById('dirInput');
        const selectDirBtn = document.getElementById('selectDirBtn');
        const fileList = document.getElementById('fileList');

        // 1. 點(diǎn)擊按鈕觸發(fā)原生 input 選擇目錄
        selectDirBtn.addEventListener('click', () => {
            dirInput.click();
        });

        // 2. 監(jiān)聽目錄選擇變化,處理文件數(shù)據(jù)
        dirInput.addEventListener('change', (e) => {
            const selectedFiles = e.target.files; // 獲取選中目錄下的所有文件(含子目錄文件)
            if (selectedFiles.length === 0) {
                fileList.innerHTML = '<div class="p-4 text-center text-gray-500">未選擇任何文件</div>';
                return;
            }
            
            // 3. 解析文件數(shù)據(jù)并渲染到頁面
            let fileHtml = '';
            Array.from(selectedFiles).forEach(file => {
                // 判斷是否為目錄(通過 type 為空且 size 為 0 間接判斷)
                const isDir = file.type === '' && file.size === 0;
                // 獲取文件在目錄中的相對路徑(webkitRelativePath 為非標(biāo)準(zhǔn)屬性,但主流瀏覽器支持)
                const relativePath = file.webkitRelativePath || file.name;
                // 格式化文件大?。ㄝo助函數(shù))
                const fileSize = isDir ? '—' : formatFileSize(file.size);

                fileHtml += `
                    <div class="file-item">
                        <span class="file-icon ${isDir ? 'text-yellow-500' : 'text-gray-400'}">
                            ${isDir ? '??' : '??'}
                        </span>
                        <div class="file-info">
                            <div class="font-medium">${file.name}</div>
                            <div class="text-xs text-gray-500">${relativePath}</div>
                        </div>
                        <div class="file-size text-sm">${fileSize}</div>
                    </div>
                `;
            });

            fileList.innerHTML = fileHtml;
        });

        // 輔助函數(shù):格式化文件大小(Bytes → KB/MB/GB)
        function formatFileSize(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const units = ['Bytes', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return `${(bytes / Math.pow(k, i)).toFixed(2)} ${units[i]}`;
        }
    </script>
</body>
</html>

3. 關(guān)鍵特性與限制

優(yōu)勢:兼容性強(qiáng)(支持 Chrome 15+、Firefox 4+、Safari 6+),無需額外依賴,實(shí)現(xiàn)簡單。

限制

  1. 無法直接識(shí)別 “目錄” 類型,需通過 typesize 間接判斷;
  2. 僅能獲取選中目錄下的 “扁平化文件列表”,無法遞歸獲取子目錄結(jié)構(gòu);
  3. 無文件讀寫能力,僅能獲取元數(shù)據(jù)。

三、方案二:基于 FileSystem Access API 實(shí)現(xiàn)(功能優(yōu)先)

1. 方案概述

FileSystem Access API 是 W3C 正在標(biāo)準(zhǔn)化的現(xiàn)代 API(目前主要支持 Chromium 內(nèi)核瀏覽器,如 Chrome 86+、Edge 86+),提供 “目錄選擇、遞歸遍歷、文件讀寫、持久化權(quán)限” 等更強(qiáng)大的能力。通過 window.showDirectoryPicker() 直接請求用戶授權(quán),授權(quán)后可主動(dòng)遍歷目錄結(jié)構(gòu),支持復(fù)雜的文件操作。

2. 完整使用示例

2.1 HTML 結(jié)構(gòu)(含子目錄遍歷功能)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>FileSystem Access API 目錄訪問示例</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        .dir-tree-item { padding: 4px 0 4px 16px; border-left: 1px solid #eee; }
        .dir-header { display: flex; align-items: center; cursor: pointer; padding: 4px 0; }
        .dir-icon { margin-right: 8px; }
        .file-meta { color: #666; font-size: 14px; margin-left: 8px; }
    </style>
</head>
<body class="p-8 bg-gray-50">
    <div class="max-w-4xl mx-auto bg-white p-6 rounded-lg shadow">
        <h2 class="text-2xl font-bold mb-4">FileSystem Access API 目錄遍歷</h2>
        <!-- 觸發(fā)目錄選擇按鈕 -->
        <button id="openDirBtn" class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600">
            打開并遍歷目錄
        </button>
        
        <!-- 目錄樹展示區(qū) -->
        <div class="mt-4 border rounded-lg p-4 max-h-80 overflow-y-auto">
            <div id="dirTree" class="text-gray-500">
                請點(diǎn)擊按鈕選擇目錄
            </div>
        </div>
    </div>

    <script>
        // 2.2 JavaScript 邏輯實(shí)現(xiàn)(含遞歸遍歷)
        const openDirBtn = document.getElementById('openDirBtn');
        const dirTree = document.getElementById('dirTree');

        openDirBtn.addEventListener('click', async () => {
            try {
                // 1. 檢查瀏覽器兼容性
                if (!window.showDirectoryPicker) {
                    alert('您的瀏覽器不支持該功能,請使用 Chrome 或 Edge 瀏覽器');
                    return;
                }

                // 2. 請求用戶選擇目錄(獲取 DirectoryHandle 對象)
                const dirHandle = await window.showDirectoryPicker({
                    mode: 'read', // 權(quán)限模式:read(只讀)/ readwrite(讀寫)
                    startIn: 'documents' // 默認(rèn)打開目錄(可選:documents、downloads 等)
                });

                // 3. 遞歸遍歷目錄結(jié)構(gòu)并渲染
                dirTree.innerHTML = '<div class="text-center text-gray-500">正在讀取目錄...</div>';
                const treeHtml = await renderDirectoryTree(dirHandle, 0);
                dirTree.innerHTML = treeHtml;

            } catch (err) {
                // 捕獲用戶取消選擇或權(quán)限拒絕錯(cuò)誤
                if (err.name === 'AbortError') {
                    dirTree.innerHTML = '<div class="text-center text-gray-500">用戶取消選擇</div>';
                } else {
                    dirTree.innerHTML = `<div class="text-center text-red-500">錯(cuò)誤:${err.message}</div>`;
                    console.error('目錄訪問失?。?, err);
                }
            }
        });

        /**
         * 遞歸渲染目錄樹
         * @param {DirectoryHandle} handle - 目錄/文件句柄
         * @param {number} depth - 目錄深度(用于縮進(jìn))
         * @returns {string} 目錄樹 HTML
         */
        async function renderDirectoryTree(handle, depth) {
            const isDir = handle.kind === 'directory';
            const indent = 'margin-left: ' + (depth * 16) + 'px;'; // 按深度縮進(jìn)
            let itemHtml = '';

            if (isDir) {
                // 處理目錄:添加展開/折疊功能
                itemHtml += `
                    <div class="dir-header" style="${indent}" onclick="toggleDir(this)">
                        <span class="dir-icon text-yellow-500">??</span>
                        <span class="font-medium">${handle.name}</span>
                        <span class="file-meta">(目錄)</span>
                    </div>
                    <div class="dir-children" style="display: none;">
                `;

                // 遍歷目錄下的所有子項(xiàng)(遞歸)
                for await (const childHandle of handle.values()) {
                    itemHtml += await renderDirectoryTree(childHandle, depth + 1);
                }

                itemHtml += '</div>'; // 閉合 dir-children

            } else {
                // 處理文件:獲取文件大小等元數(shù)據(jù)
                const file = await handle.getFile();
                const fileSize = formatFileSize(file.size);
                itemHtml += `
                    <div style="${indent} display: flex; align-items: center; padding: 4px 0;">
                        <span class="dir-icon text-gray-400">??</span>
                        <span>${handle.name}</span>
                        <span class="file-meta">${fileSize}</span>
                    </div>
                `;
            }

            return itemHtml;
        }

        // 目錄展開/折疊切換(全局函數(shù),用于 HTML 內(nèi)聯(lián)調(diào)用)
        function toggleDir(el) {
            const children = el.nextElementSibling;
            children.style.display = children.style.display === 'none' ? 'block' : 'none';
            el.querySelector('.dir-icon').textContent = children.style.display === 'none' ? '??' : '??';
        }

        // 復(fù)用文件大小格式化函數(shù)(同方案一)
        function formatFileSize(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const units = ['Bytes', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return `${(bytes / Math.pow(k, i)).toFixed(2)} ${units[i]}`;
        }
    </script>
</body>
</html>

3. 關(guān)鍵特性與限制

優(yōu)勢

  1. 直接識(shí)別 “目錄 / 文件” 類型(通過 handle.kind);
  2. 支持遞歸遍歷目錄結(jié)構(gòu),可實(shí)現(xiàn) “目錄樹” 交互;
  3. 提供文件讀寫能力(通過 fileHandle.createWritable());
  4. 可請求持久化權(quán)限(handle.requestPermission()),下次訪問無需重新授權(quán)。

限制:兼容性差,僅支持 Chromium 內(nèi)核瀏覽器,F(xiàn)irefox 和 Safari 暫不支持。

四、兩種方案對比分析

對比維度方案一(File API)方案二(FileSystem Access API)
瀏覽器兼容性強(qiáng)(支持所有現(xiàn)代瀏覽器)弱(僅 Chromium 內(nèi)核瀏覽器)
目錄識(shí)別能力間接判斷(依賴 type 和 size)直接識(shí)別(handle.kind)
目錄遍歷能力僅扁平化列表,無遞歸支持支持遞歸遍歷,可構(gòu)建目錄樹
文件操作能力僅讀取元數(shù)據(jù),無讀寫能力支持文件讀寫、刪除等完整操作
權(quán)限持久化不支持(每次刷新需重新選擇)支持(可請求持久化權(quán)限)
交互體驗(yàn)依賴隱藏 input,體驗(yàn)較基礎(chǔ)原生 API 調(diào)用,體驗(yàn)更流暢
適用場景兼容性優(yōu)先的簡單目錄查看需求現(xiàn)代瀏覽器下的復(fù)雜文件管理需求

五、注意事項(xiàng)與最佳實(shí)踐

  • 安全合規(guī):無論哪種方案,都必須通過 “用戶主動(dòng)操作” 觸發(fā)授權(quán)(如點(diǎn)擊按鈕),禁止自動(dòng)觸發(fā)目錄選擇,否則瀏覽器會(huì)攔截操作。
  • 錯(cuò)誤處理:需捕獲 “用戶取消選擇”(AbortError)和 “權(quán)限拒絕”(PermissionDeniedError)等錯(cuò)誤,避免頁面展示異常。
  • 兼容性適配:可通過 “特性檢測” 實(shí)現(xiàn)方案降級(jí),例如:
if (window.showDirectoryPicker) {
    // 使用方案二(FileSystem Access API)
} else {
    // 使用方案一(File API)
}
  • 性能優(yōu)化:遍歷大量文件時(shí)(如超過 1000 個(gè)文件),建議使用 “分頁加載” 或 “虛擬滾動(dòng)”,避免一次性渲染導(dǎo)致頁面卡頓。
  • 隱私保護(hù):不建議存儲(chǔ)用戶本地文件路徑等敏感信息,僅在前端臨時(shí)處理文件數(shù)據(jù),避免隱私泄露風(fēng)險(xiǎn)。

以上就是前端JavaScript獲取本地文件目錄內(nèi)容的兩種實(shí)現(xiàn)方案的詳細(xì)內(nèi)容,更多關(guān)于前端JS獲取本地文件目錄內(nèi)容的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • javascript 函數(shù)及作用域總結(jié)介紹

    javascript 函數(shù)及作用域總結(jié)介紹

    本文是對javascript在的函數(shù)及作用域進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-11-11
  • 4種JavaScript實(shí)現(xiàn)簡單tab選項(xiàng)卡切換的方法

    4種JavaScript實(shí)現(xiàn)簡單tab選項(xiàng)卡切換的方法

    這篇文章主要介紹了4種JavaScript實(shí)現(xiàn)簡單tab選項(xiàng)卡切換的方法,感興趣的小伙伴們可以參考一下
    2016-01-01
  • 微信小程序?qū)崿F(xiàn)下拉刷新動(dòng)畫

    微信小程序?qū)崿F(xiàn)下拉刷新動(dòng)畫

    這篇文章主要為大家詳細(xì)介紹了微信小程序動(dòng)畫實(shí)現(xiàn)下拉刷新動(dòng)畫,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • ES6擴(kuò)展運(yùn)算符的理解與使用場景

    ES6擴(kuò)展運(yùn)算符的理解與使用場景

    擴(kuò)展運(yùn)算符( spread )是三個(gè)點(diǎn)(...),它好比 rest 參數(shù)的逆運(yùn)算,將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列,這篇文章主要給大家介紹了關(guān)于ES6擴(kuò)展運(yùn)算符的理解與使用場景的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • ES6 系列之 Generator 的自動(dòng)執(zhí)行的方法示例

    ES6 系列之 Generator 的自動(dòng)執(zhí)行的方法示例

    這篇文章主要介紹了ES6 系列之 Generator 的自動(dòng)執(zhí)行的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-10-10
  • 詳解js常用分割取字符串的方法

    詳解js常用分割取字符串的方法

    這篇文章主要介紹了js常用分割取字符串的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • 詳解JavaScript中的強(qiáng)制類型轉(zhuǎn)換

    詳解JavaScript中的強(qiáng)制類型轉(zhuǎn)換

    這篇文章主要介紹了JavaScript中的強(qiáng)制類型轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 淺析創(chuàng)建javascript對象的方法

    淺析創(chuàng)建javascript對象的方法

    下面小編就為大家?guī)硪黄獪\析創(chuàng)建javascript對象的方法。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-05-05
  • 前端MQTT詳細(xì)使用的兩種方法

    前端MQTT詳細(xì)使用的兩種方法

    MQTT(消息隊(duì)列遙測傳輸協(xié)議),是一種基于發(fā)布/訂閱(publish/subscribe)模式的通訊協(xié)議,該協(xié)議構(gòu)建于TCP/IP協(xié)議上,這篇文章主要給大家介紹了關(guān)于前端MQTT詳細(xì)使用的兩種方法,需要的朋友可以參考下
    2024-07-07
  • 8 個(gè)有用的JS技巧(推薦)

    8 個(gè)有用的JS技巧(推薦)

    這篇文章主要介紹了8 個(gè)有用的JS技巧(推薦),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-07-07

最新評(píng)論

石景山区| 天柱县| 万盛区| 齐齐哈尔市| 汉阴县| 页游| 平顺县| 安多县| 台南县| 分宜县| 桦川县| 黄浦区| 增城市| 满城县| 双城市| 徐州市| 库车县| 本溪市| 诏安县| 平果县| 台东县| 凤凰县| 武宁县| 伊宁县| 友谊县| 曲周县| 安溪县| 米林县| 广东省| 竹北市| 达州市| 宁阳县| 兰坪| 定州市| 南投市| 沙河市| 潞城市| 乐陵市| 红河县| 肇东市| 神木县|