showSaveFilePicker是File System Access API中用于弹出本地文件保存对话框的方法,需HTTPS环境、用户手势触发,返回FileSystemFileHandle后必须调用createWritable()写入并close(),否则静默失败;仅Chrome 86+、Edge 91+支持,Firefox和Safari不支持。

showSaveFilePicker 是什么,为什么不能直接用
showSaveFilePicker 是 Web API 中 Window.showSaveFilePicker() 方法,属于 File System Access API,它允许网页主动弹出保存对话框,让用户选择本地路径并写入文件。但它不是“直接保存”,而是返回一个 FileSystemFileHandle,后续必须通过它获取可写流(writable)再写入内容——跳过这步会报错或静默失败。
常见错误现象:Uncaught TypeError: showSaveFilePicker is not a function,原因很可能是:未启用实验性功能、未在 HTTPS 环境运行、或浏览器不支持(仅 Chrome 86+、Edge 91+ 支持,Firefox 和 Safari 当前不支持)。
如何正确调用 showSaveFilePicker 并写入文件
必须满足三个前提:HTTPS 协议、用户手势触发(如 click)、且浏览器支持。以下是最小可行示例:
async function saveToFile() {
try {
const handle = await window.showSaveFilePicker({
types: [{
description: 'Text file',
accept: { 'text/plain': ['.txt'] }
}],
suggestedName: 'output.txt'
});
const writable = await handle.createWritable();
await writable.write('Hello, world!');
await writable.close();
} catch (err) {
console.error(err.name, err.message);
}
}
关键点说明:
立即学习“前端免费学习笔记(深入)”;
-
types参数控制文件类型过滤,accept字段的 key 是 MIME 类型,value 是扩展名数组;漏写或格式错误会导致类型筛选失效 -
suggestedName只影响默认文件名,不强制扩展名匹配accept,但若用户手动输入不匹配的扩展名(如输入report.pdf但accept只含.txt),Chrome 会自动重置为.txt - 必须显式调用
writable.close(),否则内容可能未刷入磁盘,尤其在写入大文件时容易丢数据
如何处理二进制内容(如 Blob、ArrayBuffer)
writable.write() 接收 string、Blob、ArrayBuffer 或 Uint8Array。但注意:Blob 写入时不会自动解包,需用 blob.stream() 或先转为 ArrayBuffer:
const blob = new Blob(['<h1>Report</h1>'], { type: 'text/html' });
const writable = await handle.createWritable();
// ✅ 正确:流式写入
await writable.write(blob.stream());
await writable.close();
// ❌ 错误:直接 write(blob) 会写入 "[object Blob]"
// await writable.write(blob);
性能提示:对大文件(>10MB),建议分块写入 + await writable.write(chunk),避免内存暴涨;createWritable({ keepExistingData: true }) 可用于追加模式(但仅限已存在文件且用户重新选中)。
兼容性 fallback 怎么做
目前无法优雅降级到 download 属性(因为 showSaveFilePicker 允许用户自定义路径,而 a[download] 只能触发浏览器默认下载行为)。最务实的做法是:
- 先检测支持性:
if ('showSaveFilePicker' in window) - 不支持时,退回到生成 Blob URL +
<a download="file.txt" href="..."></a>自动点击 - 注意:Blob URL 下载无法指定保存路径,且部分浏览器(如 Safari)会阻止非用户手势触发的自动下载
- 不要尝试 polyfill —— File System Access API 依赖底层沙箱权限,无法用 JS 模拟
真正容易被忽略的是权限持久化:用户首次授权后,Chrome 会记住该 origin 的访问偏好,但若用户在系统级关闭了网站的“本地文件访问”权限(Chrome 设置 → 隐私设置和安全性 → 网站设置 → 文件访问),后续调用会直接拒绝,且不弹窗。这时候 showSaveFilePicker 会抛出 NotAllowedError,需要引导用户手动开启。



















