createWritable 是 File System Access API 中用于创建可写流的方法,需基于用户授权的 FileSystemFileHandle 调用;与传统 File API(如 FileReader、Blob URL)仅支持读取或一次性下载不同,它支持原地覆盖写、原子化落盘(须显式 close),且不依赖服务器中转。

createWritable 是什么,它和传统 file API 有什么区别
createWritable 是 File System Access API 的核心方法之一,用于获取一个可写入的 FileSystemWritableFileStream 对象。它不直接操作 Blob 或 File,而是作用于用户通过 showSaveFilePicker 或 showOpenFilePicker(配合 mode: "readwrite")获得的 FileSystemFileHandle。这意味着你必须先有合法的文件句柄,不能凭空创建写入流——浏览器会拒绝无用户手势触发、无显式授权的写入请求。
常见错误现象:Uncaught TypeError: handle.createWritable is not a function,通常是因为用了旧版 Chrome(showOpenFilePicker 默认只读)。
如何正确调用 createWritable 获取写入流
关键前提是:必须由用户主动触发(如点击按钮),且句柄需具备写权限。以下是最小可行路径:
- 调用
showSaveFilePicker获取可写句柄(推荐用于新建/覆盖场景) - 或用
showOpenFilePicker({ mode: "readwrite" })打开已有文件(需用户确认“允许修改”) - 再对返回的
FileSystemFileHandle调用createWritable()
示例代码:
async function getWritableStream() {
try {
const handle = await window.showSaveFilePicker({
types: [{ description: "Text file", accept: { "text/plain": [".txt"] } }]
});
const writable = await handle.createWritable(); // ✅ 正确:handle 来自 save picker
return writable;
} catch (err) {
console.error(err.name, err.message); // 如 "NotAllowedError", "User cancelled"
}
}
createWritable 的 options 参数影响写入行为
createWritable 接收一个可选 options 对象,目前仅支持 keepExistingData 布尔值(Chrome 117+),它控制是否保留原文件内容:
-
keepExistingData: true(默认):写入从文件开头开始,但不会自动清空原内容;若新数据比原文件短,末尾残留旧字节 -
keepExistingData: false:等效于 truncate,写入前清空整个文件(更安全,避免脏数据)
注意:这个选项只在句柄来自 showOpenFilePicker({ mode: "readwrite" }) 时生效;showSaveFilePicker 返回的新文件天然为空,keepExistingData 无实际效果。
将 WCAG 2 AA 无障碍标准应用于设计系统、UI 组件和网页——通过可运行的验证器进行对比度计算,采用设计 token 模式使颜色天生可访问,设定排版和焦点状态规则,并提供语义检查清单。适用于构建或审查 UI。
示例:
const writable = await handle.createWritable({ keepExistingData: false });
写入完成后必须调用 close(),否则文件可能损坏或不更新
FileSystemWritableFileStream 是流式写入,数据不会立即落盘。常见坑是忘记 close() 或没处理 abort() 异常:
- 只调用
writable.write()但不await writable.close()→ 文件内容可能为空或截断 - 写入中途抛错未捕获 → 流处于 pending 状态,后续无法重用该句柄
- 想取消写入?必须用
writable.abort(),不能只丢弃 Promise
安全写法建议用 try/finally:
const writable = await handle.createWritable();
try {
await writable.write("hello world");
await writable.write(new Uint8Array([10, 11, 12])); // 写入二进制
} finally {
await writable.close(); // ✅ 必须确保执行
}
跨平台兼容性差:目前仅 Chromium 系(Chrome/Edge ≥102,部分 Android 版本)支持,Firefox 和 Safari 完全不支持。生产环境需做降级(如回退到 download 属性触发下载)。
真正容易被忽略的是:即使用户点了保存,句柄也只在当前页面生命周期内有效;刷新后无法复用,必须重新 pick。如果需要持久化编辑能力,得配合 IndexedDB 缓存内容,再择机同步到文件系统。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










