navigator.storage.getdirectory() 必须在安全上下文(https/localhost)且用户已交互后调用,返回 filesystemdirectoryhandle 句柄而非文件内容,需通过 getfilehandle→getfile→text/arraybuffer 读取,写入须严格三段式 createwritable→write→close,句柄无法持久化存储,刷新即失效。

navigator.storage.getDirectory 不是 HTML 的功能,它根本不能通过 HTML 标签、属性或表单触发——必须用 JavaScript 在安全上下文里主动调用,且依赖用户已发生过交互。直接在 <script></script> 里写就报错,不是你代码错了,是环境或时机不对。
为什么 navigator.storage.getDirectory 返回 undefined 或抛 NotSupportedError
两个硬性前提没满足,它就一定失败:
-
self.isSecureContext必须为true:只认https://或http://localhost,http://127.0.0.1、file://、内网 IP 都不行 - 必须有 recent user activation:页面加载完不能立刻调,得等用户点一下按钮、按一次键再触发;放在
DOMContentLoaded、setTimeout或自动播放逻辑里全会失败
验证方式:打开控制台,输入 self.isSecureContext && document.hasStorageAccess(),两个都返回 true 才算过关。
navigator.storage.getDirectory() 拿到的是句柄,不是文件内容
它返回一个 FileSystemDirectoryHandle,只是个指向沙箱根目录的“钥匙”,不加载任何实际数据。常见误解是以为拿到句柄就能直接读写文件——其实连子项列表都没加载。
- 遍历子项要用
for await (const entry of handle.values()),别用Array.from(await handle.keys()),后者会把整个目录树拉进内存,万级文件直接卡死 UI - 读单个文件要先
handle.getFileHandle('name.txt'),再fileHandle.getFile(),最后才能调.text()或.arrayBuffer() - 写文件必须三段式:
createWritable()→write()→close();漏掉close()就等于没写,文件内容为空或残留旧版本
如何让 OPFS 句柄在刷新后还能用
OPFS 本身不持久化句柄,刷新后 getDirectory() 会返回新句柄,但旧句柄失效。想长期访问(比如存海量素材),得做两件事:
- 调
handle.requestPermission({ mode: 'readwrite' })并await navigator.storage.persist(),然后检查await navigator.storage.persisted()是否为true - 不能把句柄存
localStorage或IndexedDB,要存handle.toWellKnownString()字符串;后续恢复需靠self.showOpenFilePicker()或self.showDirectoryPicker()手动重建(getDirectory()无法从字符串还原)
注意:所谓“持久化”只是延长当前 origin 下的免弹窗窗口期,不是永久授权。用户清缓存、换浏览器、或长时间未访问,权限仍可能失效。
最常被忽略的一点:OPFS 是纯 JS 驱动的原子写入系统,没有“临时保存”概念。每次 createWritable() 都开辟新缓冲区,close() 是唯一落盘动作——这个设计决定了你没法靠 try/catch 捕获写失败,只能靠 close() 的 Promise reject 来判断成败。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











