write()必须配合createwritable()使用,不能直接调用或手动构造;仅支持arraybuffer、typedarray、blob,字符串需先用textencoder编码;必须显式调用close()才能落盘。

write() 方法必须配合 createWritable() 使用,不能直接 new
FileSystemWritableFileStream 的 write() 不是一个独立可调用的函数,它只在通过 createWritable() 返回的流实例上存在。试图手动构造或复用旧流会导致 TypeError: Illegal invocation 或 InvalidStateError。
常见错误是误以为能缓存流对象多次写入——实际上每个 write() 调用都应基于一次新的 createWritable(),或在单次流生命周期内连续调用(见下一点):
- ✅ 正确:先
await file.createWritable(),再对返回的流连续调用write()、write()、close() - ❌ 错误:保存流对象后隔几秒再
stream.write(...)—— 流可能已关闭或失效 - ❌ 错误:用
new FileSystemWritableFileStream(...)—— 该构造函数不存在,浏览器会报ReferenceError
write() 接收三种数据类型:ArrayBuffer、TypedArray、Blob
write() 不接受字符串或普通对象。传入 string 会静默失败或抛出 TypeError: The provided value is not of type '(ArrayBuffer or ArrayBufferView or Blob)'。
必须显式编码字符串为字节序列:
- 用
new TextEncoder().encode('hello')→ 得到Uint8Array - 用
new Blob(['hello']).arrayBuffer()→ 得到ArrayBuffer(需 await) - 直接传
Uint8Array、Int32Array等 TypedArray 也可,但注意字节序和内容含义
示例:
const stream = await file.createWritable();
await stream.write(new TextEncoder().encode('Hello OPFS\n'));
await stream.write(new Uint8Array([0x01, 0x02, 0x03]));
await stream.close();
write() 支持 offset 参数,但仅对 seekable 流有效
OPFS 文件默认支持随机写入,所以 write() 可以带 { at: number } 选项指定写入位置,例如覆盖某段内容:
-
await stream.write(data, { at: 1024 })→ 从第 1024 字节开始写 - 不传
at时,写入位置由内部指针控制:首次写入从 0 开始,后续写入接续上一次末尾(类似追加) - 若想覆盖而非追加,必须显式传
at;否则反复write()会不断延长文件
注意:at 是字节偏移量,不是字符数;中文字符经 UTF-8 编码后占多个字节,不能直接用 str.length 计算。
close() 必须显式调用,否则数据可能未落盘
write() 是异步写入,但数据仍可能停留在内存缓冲区。不调用 close() 就结束作用域,会导致写入不完整甚至丢失——尤其在写入大文件或快速连续操作时。
- ✅ 必须:每次写入流程结尾加
await stream.close() - ⚠️ 风险:用
finally块包裹close(),防止异常中断导致流未关闭 - ❌ 不要依赖垃圾回收:OPFS 流不会自动 flush 或 close
典型安全写法:
let stream;
try {
stream = await file.createWritable();
await stream.write(new TextEncoder().encode('data'));
} finally {
if (stream) await stream.close();
}
OPFS 的 write() 行为高度依赖流的生命周期管理,最易忽略的是 close() 的必要性,以及字符串必须编码成二进制这一前提——这两点一旦遗漏,现象往往是“没报错但文件为空”或“内容截断”。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











