File、Blob 和 ArrayBuffer 经常同时出现在浏览器文件流程里,但职责不同:File 描述用户选择的输入,Blob 用媒体类型封装不可变字节,ArrayBuffer 向解析器和编解码器暴露原始内存。
明确这些边界,可以避免 Base64 体积膨胀、重复内存复制、错误 MIME 类型,以及处理压缩包、图片、PDF 或音频时的内存峰值。
核心区别
File 继承 Blob,并增加 name、lastModified 和可选相对路径。ArrayBuffer 是没有文件名和 MIME 的固定长度内存;Uint8Array 与 DataView 是这段内存上的不同解释。
| 类型 | 携带内容 | 典型职责 |
|---|---|---|
| File | Blob 字节与来源元数据 | 用户选择的输入 |
| Blob | 不可变字节与 MIME | 输出、预览、下载 |
| ArrayBuffer | 原始固定内存 | 解析器或编解码输入 |
| Uint8Array | Buffer 上的字节视图 | 读取或修改字节 |
| ReadableStream | 随时间到达的数据块 | 增量处理 |
File 是输入契约,不是磁盘句柄
File 是用户通过选择器、拖放、剪贴板或明确授权的文件系统句柄交付给网页的内容快照,网页不能借此遍历任意本地路径。
arrayBuffer()、text()、stream() 和 slice() 都是本地读取。只有代码主动把值交给 fetch、XMLHttpRequest 或 WebSocket 时才发生上传。
Blob 封装二进制结果
结果需要 image/webp、application/pdf 或 application/zip 等类型时,Blob 很合适。它可以切片、传给 createImageBitmap、生成 Blob URL 或通过下载链接保存。
Blob 不可变,典型转换是 Blob → ArrayBuffer → 类型化数组或处理库 → 新 Blob,输入和输出保持分离。
const file = input.files![0];
const bytes = new Uint8Array(await file.arrayBuffer());
const output = new Blob([bytes], { type: 'application/octet-stream' });ArrayBuffer 负责字节层
ArrayBuffer 持有内存但不规定解释方式。Uint8Array 读取无符号字节,DataView 按指定字节序读取多字节数值。
ZIP、Web Crypto、图片编解码器与二进制解析器需要精确字节,因此接收 Buffer 或类型化数组。视图可以避免复制,slice、拼接和未 transfer 的克隆则可能重新分配。
转换存在内存成本
await blob.arrayBuffer() 会把完整 Blob 物化到内存。TextEncoder 把字符串转为 UTF-8 字节,TextDecoder 反向转换。Base64 是文本表示,通常不适合内部处理。
大文件流程可能同时保留 File、ArrayBuffer、解码像素和输出 Blob。应尽量切片或流式处理,把 Buffer transfer 给 Worker,并释放旧 Blob URL。
- 输入边界使用 File。
- 二进制输出与下载使用 Blob。
- 解析器内部使用 ArrayBuffer 或类型化数组。
- 可增量格式使用 Stream。
- 只有纯文本接口要求时才用 Base64。
ToolGarden 实例
ZIP 工具把 File 读为 Uint8Array,交给 fflate 后封装为 application/zip Blob;图片工具解码 File,处理像素,再从 Canvas 或编解码器得到新 Blob。
这些类型不会自动保证隐私,隐私来自没有把它们加入出站请求。
总结
用 File 承载输入,用 ArrayBuffer 与类型化数组处理字节,用 Blob 封装输出,再用 Blob URL 提供临时访问。这比把所有内容转成字符串更清晰高效。