跳转到内容

能力 · API

File System Access API

发布于 更新于

有限可用不支持的浏览器: Chrome (Android)、Safari (iOS)、Safari (macOS)、Firefox (Desktop)WICG 草案

File System Access API 让页面打开、编辑并保存用户设备上的真实文件和文件夹:showOpenFilePicker()、showSaveFilePicker() 与 showDirectoryPicker() 返回 FileSystemFileHandle 和 FileSystemDirectoryHandle 对象,它们在选择器关闭后仍然有效,可以存进 IndexedDB,并通过 createWritable() 写回同一个文件。句柄接口本身由 WHATWG File System Standard 定义,与 Origin Private File System 共用。

选择器只有 Chromium 实现:桌面端的 Chrome 86 与 Edge 86。Firefox 111 与 Safari 15.2 为 OPFS 实现了句柄接口但不提供选择器,Safari 直到 Safari 26 才加入 createWritable()(BCD api.Window.showOpenFilePicker、api.FileSystemFileHandle.createWritable)。句柄上的 queryPermission() 与 requestPermission() 只有 Chrome 86 支持。

window.showOpenFilePicker()
window.showOpenFilePicker(options)
window.showSaveFilePicker()
window.showSaveFilePicker(options)
window.showDirectoryPicker()
window.showDirectoryPicker(options)

showOpenFilePicker() 返回 Promise<sequence<FileSystemFileHandle>>(除非 multiple 为 true,否则只有一个元素);showSaveFilePicker() 返回 Promise<FileSystemFileHandle>;showDirectoryPicker() 返回 Promise<FileSystemDirectoryHandle>。三者都带 [SecureContext],并要求瞬时用户激活。保存选择器返回的句柄已带读写权限,而且 showSaveFilePicker() 在 Promise 兑现的那一刻就清空所选文件,不是等你之后 close() 可写流时。

每个选择器接受一个可选的 options 字典。OpenFilePickerOptions 与 SaveFilePickerOptions 继承共享的 FilePickerOptions;DirectoryPickerOptions 独立定义。

成员 类型 必填 适用于 说明
types sequence<FilePickerAcceptType> 否 open、save 供用户选择的过滤器。每一项有 description(USVString,默认 "")和一个 accept 记录,把 MIME 类型映射到一个后缀或后缀列表,例如 { "text/plain": [".txt", ".md"] }。
excludeAcceptAllOption boolean 否 open、save 默认 false。为 true 时省略「所有文件」过滤器;types 为空时无论如何都会加上。
id DOMString 否 全部 最多 32 个字符,只能是字母、数字、_ 或 -。浏览器按源记住该 id 上次使用的目录,下次从那里开始。
startIn WellKnownDirectory 或 FileSystemHandle 否 全部 起始位置:"desktop"、"documents"、"downloads"、"music"、"pictures"、"videos" 之一,或之前选择得到的句柄。id 记住的目录优先。
multiple boolean 否 open 默认 false。为 true 时用户可选任意数量的文件。
suggestedName USVString? 否 save 预填文件名;浏览器可能清洗或忽略它认为危险的名字。
mode FileSystemPermissionMode 否 directory "read"(默认)或 "readwrite"。用 "readwrite" 时权限提示一并覆盖写入,所选目录不需要第二次提示。

accept 中的后缀必须以 . 开头、不能以 . 结尾、最长 16 个字符,并且只能包含合法的后缀码点。

选择器按下列顺序拒绝;SecurityError 与 TypeError 两类在任何对话框出现之前检查。

异常 条件
SecurityError 文档的源是 opaque origin(沙箱 iframe);或其源与顶层源不同(跨源 iframe);或窗口没有瞬时用户激活。
TypeError accept 的键不是合法 MIME 类型或带参数;某个后缀违反上述规则;types 加上「所有文件」选项后仍没有任何过滤器;id 超过 32 个字符或含其他字符。
AbortError 用户未选择就关闭了对话框;或浏览器判定所选内容过于敏感(系统文件夹、整个下载目录)并选择拒绝而非重开对话框;或对 showDirectoryPicker() 而言,权限请求的结果不是 "granted"。

之后对返回句柄的操作抛的是 File System Standard 的错误:权限未授予时为 NotAllowedError,文件被删除或移动时为 NotFoundError,另一个可写流或同步访问句柄持有锁时为 NoModificationAllowedError。

每个示例都精确检测即将调用的方法;Firefox 与 Safari 虽然为 OPFS 暴露了 FileSystemFileHandle,但 "showOpenFilePicker" in window 仍为 false。

打开、编辑并保存文本文件,回退到 input 与下载

Section titled “打开、编辑并保存文本文件,回退到 input 与下载”

有选择器时,用户直接覆盖保存自己打开的文件。没有选择器时,<input type="file"> 负责读取,点击 <a download> 写出一份新副本;回退路径无法覆盖原文件,所以界面应写「下载」而不是「保存」。

let fileHandle = null;
const editor = document.querySelector("#editor");
const legacyInput = document.querySelector("#legacy-file");
const supported = "showOpenFilePicker" in window;
document.querySelector("#open").addEventListener("click", async () => {
if (!supported) {
legacyInput.click();
return;
}
try {
[fileHandle] = await window.showOpenFilePicker({
types: [{ description: "文本", accept: { "text/plain": [".txt", ".md"] } }],
});
editor.value = await (await fileHandle.getFile()).text();
} catch (err) {
if (err.name !== "AbortError") throw err; // 用户关闭对话框是正常情况
}
});
legacyInput.addEventListener("change", async () => {
editor.value = await legacyInput.files[0].text();
});
document.querySelector("#save").addEventListener("click", async () => {
if (!supported) {
const link = document.createElement("a");
link.href = URL.createObjectURL(new Blob([editor.value], { type: "text/plain" }));
link.download = "document.txt";
link.click();
URL.revokeObjectURL(link.href);
return;
}
fileHandle ??= await window.showSaveFilePicker({ suggestedName: "document.txt" });
const writable = await fileHandle.createWritable();
await writable.write(editor.value);
await writable.close(); // 磁盘上的文件只在这一步改变
});

写入先进入临时文件,close() 兑现时才替换目标;在 close() 之前关闭标签页,原文件保持原样。

从 IndexedDB 恢复句柄并重新检查权限

Section titled “从 IndexedDB 恢复句柄并重新检查权限”

句柄可结构化克隆,所以「最近文件」列表可以直接存句柄。权限不一定保留:先调 queryPermission(),只在状态为 "prompt" 时才在点击中调 requestPermission()。

async function reopen(db, button) {
if (!("showOpenFilePicker" in window)) return null;
const handle = await db.get("recent", "last"); // 之前选择时存下的文件句柄
if (!handle) return null;
const mode = { mode: "readwrite" };
let state = await handle.queryPermission(mode);
if (state === "prompt") {
await new Promise((resolve) => button.addEventListener("click", resolve, { once: true }));
state = await handle.requestPermission(mode);
}
return state === "granted" ? handle : null;
}

返回 null 时调用方回到选择器;"denied" 状态会一直保持,直到用户在站点设置中自行更改。

规范

规范状态
File System Access API(文件系统访问)WICG 草案
File System Access: showOpenFilePicker() methodWICG 草案
File System Access: showSaveFilePicker() methodWICG 草案
File System Access: showDirectoryPicker() methodWICG 草案
File System Standard: FileSystemFileHandle interfaceWHATWG 现行标准
  • 图例
  • 支持
  • 部分支持
  • 需开启标志
  • 不支持
  • 未知
浏览器 / 平台支持版本置信度来源备注
Chrome (Android)不支持—中来源1
Chrome (Desktop)支持86中来源—
Edge (Desktop)支持86中来源—
Safari (iOS)不支持—中来源2
Safari (macOS)不支持—中来源3
Firefox (Desktop)不支持—中来源4
Samsung Internet不支持—中来源5
  1. Android 上不暴露 showOpenFilePicker / showSaveFilePicker。
  2. 仅提供源私有文件系统(OPFS),没有用户可见的文件选择器。
  3. 没有 showOpenFilePicker;仅 OPFS。
  4. 仅 OPFS;无法访问用户可见的文件选择器。
  5. 选择器方法(`showOpenFilePicker`、`showSaveFilePicker`、`showDirectoryPicker`)在 Chromium 中仅限桌面端;Chrome for Android 没有实现,Samsung Internet 也就无从镜像(MDN 兼容性表,2026-10-03 核对)。

源数据: /compatibility/file-system-access.json · 全球使用占比: 37 % (StatCounter 2026-05)

来源: 规范 · MDN · 最近核验 2026-06-24 · 置信度: 中 (由来源计算)