浏览器中的二进制

本文将系统盘点 浏览器中操作二进制数据的 Web API,从底层内存模型到文件处理、网络传输,再到性能优化与最佳实践。
ArrayBuffer 与 DataView
ArrayBuffer
ArrayBuffer
表示一段 固定长度的二进制内存,本身不能直接读写,必须通过视图来访问。
const buf = new ArrayBuffer(16)
console.log(buf.byteLength) // 16
const buf2 = buf.slice(4, 12) // 拷贝出新 buffer
TypedArray
TypedArray
是一组基于 ArrayBuffer
的 强类型数组视图,不同类型表示不同的数值范围。
类型 | 位宽 | 说明 |
---|---|---|
Int8Array | 8位 | -128 ~ 127 |
Uint8Array | 8位 | 0 ~ 255 |
Uint8ClampedArray | 8位 | 自动裁剪到 0–255 |
Int16Array / Uint16Array | 16位 | 有符号/无符号 |
Int32Array / Uint32Array | 32位 | 有符号/无符号 |
Float32Array / Float64Array | 32/64位 | 浮点数 |
const buf = new ArrayBuffer(8)
const u8 = new Uint8Array(buf)
u8.set([1, 2, 3], 0)
console.log(u8.subarray(0, 2)) // 共享视图(零拷贝)
console.log(u8.slice(0, 2)) // 拷贝出新内存
注意
subarray
→ 零拷贝,共享内存。slice
→ 拷贝数据,返回新内存。
DataView
如果需要 精确字节控制 或者 指定大小端,请使用 DataView
。
const buf = new ArrayBuffer(6)
const dv = new DataView(buf)
dv.setUint16(0, 0xABCD, true) // 小端
dv.setInt32(2, -1000, true)
console.log(dv.getUint16(0, true).toString(16)) // abcd
console.log(dv.getInt32(2, true)) // -1000
使用场景
- 解析二进制协议
- 读取文件头(如 PNG、WAV)
- 需要跨端序的精确控制
文本与二进制转换
TextEncoder / TextDecoder(推荐)
现代浏览器推荐使用 TextEncoder
和 TextDecoder
来做字符串与 Uint8Array
的转换。
const enc = new TextEncoder()
const u8 = enc.encode("你好🌏")
const dec = new TextDecoder("utf-8")
console.log(dec.decode(u8)) // "你好🌏"
atob / btoa(旧 API)
btoa
:字符串 → base64atob
:base64 → 字符串
function u8ToBase64(u8) {
return btoa(String.fromCharCode(...u8))
}
function base64ToU8(b64) {
return Uint8Array.from(atob(b64), c => c.charCodeAt(0))
}
踩坑提醒
atob
/ btoa
仅支持 Latin-1 字符集,处理中文或 UTF-8 时容易乱码。
请优先使用 TextEncoder
/ TextDecoder
。
文件与二进制对象
Blob 与 File
- Blob:不可变的二进制数据块
- File:继承自
Blob
,带name
和lastModified
属性
const blob = new Blob([new Uint8Array([1,2,3])], { type: 'application/octet-stream' })
const file = new File([blob], "demo.bin")
const buf = await blob.arrayBuffer()
FileReader
旧版 API,用于读取 Blob
/ File
。
const reader = new FileReader()
reader.onload = () => console.log(reader.result)
reader.readAsArrayBuffer(file)
网络与流式操作
fetch 与 Response
// 下载二进制
const buf = await (await fetch('/file.bin')).arrayBuffer()
// 上传二进制
await fetch('/upload', { method: 'POST', body: new Uint8Array([1,2,3]) })
Streams API
适合大文件分块处理。
const res = await fetch('/big.bin')
const reader = res.body.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) break
console.log('chunk size:', value.byteLength)
}
WebSocket
支持二进制帧。
const ws = new WebSocket('wss://example.com')
ws.binaryType = 'arraybuffer'
ws.onmessage = e => {
const u8 = new Uint8Array(e.data)
console.log(u8)
}
跨线程与共享内存
Transferable(零拷贝)
使用 postMessage
传输时,可以转移 ArrayBuffer
避免拷贝。
worker.postMessage(u8.buffer, [u8.buffer])
SharedArrayBuffer 与 Atomics
适合多线程共享数据。
const sab = new SharedArrayBuffer(1024)
const view = new Int32Array(sab)
Atomics.store(view, 0, 42)
console.log(Atomics.load(view, 0)) // 42
前提条件
SharedArrayBuffer
需要 跨源隔离(COOP/COEP)环境,否则不可用。
高级 API
WebCrypto API
const data = new TextEncoder().encode('hello')
const digest = await crypto.subtle.digest('SHA-256', data)
console.log(new Uint8Array(digest))
WebAssembly Memory
const memory = new WebAssembly.Memory({ initial: 1 })
const u8 = new Uint8Array(memory.buffer)
u8[0] = 42
应用案例
在现代 Web 开发中,二进制流的应用非常广泛:
- 网络请求流:分块传输/上传文件
- 文件流:断点续传/大文件预览
- 音视频流:直播/点播/录制
- 实际项目:二进制协议解析、图片压缩、加密等
本章节提供系统性案例,帮助在实际开发中掌握二进制流的处理技巧
一、网络请求中的二进制流
下载大文件(流式处理)
利用 fetch + Streams API
,我们可以边下边处理,避免内存爆炸。
async function downloadBigFile(url) {
const res = await fetch(url)
const reader = res.body.getReader()
let received = 0
while (true) {
const { done, value } = await reader.read()
if (done) break
received += value.byteLength
console.log(`Received ${received} bytes`)
// 可写入 IndexedDB / Cache / 文件系统
}
}
应用场景
- 大文件下载(ISO、视频)
- 实时数据流(日志/行情)
- 边下载边解压/解码
上传文件(二进制分片)
async function uploadFile(file, chunkSize = 1024 * 1024) {
let offset = 0
while (offset < file.size) {
const chunk = file.slice(offset, offset + chunkSize)
await fetch('/upload', {
method: 'POST',
body: chunk
})
offset += chunkSize
console.log(`Uploaded ${Math.min(offset, file.size)}/${file.size}`)
}
}
注意
- 服务端需支持分片合并
- 可搭配断点续传(记录 offset)
二、 文件读写中的二进制流
FileReader + ArrayBuffer
function readFileAsBinary(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => resolve(new Uint8Array(reader.result))
reader.onerror = reject
reader.readAsArrayBuffer(file)
})
}
File System Access API(新)
可直接读写本地文件(需 HTTPS)。
// 保存文件
async function saveFile(u8) {
const handle = await window.showSaveFilePicker()
const writable = await handle.createWritable()
await writable.write(u8)
await writable.close()
}
应用场景
- 文件预览(PDF、图片、二进制日志)
- 客户端数据缓存
- 本地编辑器/IDE
三、 音频/视频二进制流
MediaSource API(边播边下)
async function playVideo(url) {
const video = document.querySelector("video")
const mediaSource = new MediaSource()
video.src = URL.createObjectURL(mediaSource)
mediaSource.addEventListener("sourceopen", async () => {
const sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp9"')
const res = await fetch(url)
const reader = res.body.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) break
sourceBuffer.appendBuffer(value)
}
})
}
应用场景
- 点播视频(边下边播)
- 直播流分发
Web Audio API(音频流播放)
async function playAudio(url) {
const ctx = new AudioContext()
const res = await fetch(url)
const buf = await res.arrayBuffer()
const audioBuf = await ctx.decodeAudioData(buf)
const source = ctx.createBufferSource()
source.buffer = audioBuf
source.connect(ctx.destination)
source.start()
}
应用场景
- 音频播放器
- 实时语音处理(配合
MediaStream
)
四、其他二进制流案例
图片压缩(Canvas + Blob)
async function compressImage(file) {
const img = await createImageBitmap(file)
const canvas = document.createElement('canvas')
canvas.width = img.width / 2
canvas.height = img.height / 2
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
return new Promise(resolve => {
canvas.toBlob(blob => resolve(blob), 'image/jpeg', 0.7)
})
}
二进制协议解析(DataView)
假设协议结构为: [magic(4字节)][version(2字节, 小端)][flags(2字节, 大端)]
function parsePacket(u8) {
const dv = new DataView(u8.buffer)
const magic = String.fromCharCode(...u8.subarray(0, 4))
const version = dv.getUint16(4, true)
const flags = dv.getUint16(6, false)
return { magic, version, flags }
}
加密/解密(WebCrypto)
async function sha256(data) {
const u8 = new TextEncoder().encode(data)
const digest = await crypto.subtle.digest("SHA-256", u8)
return Array.from(new Uint8Array(digest)).map(b => {
return b.toString(16).padStart(2, '0')
}).join('')
}
二进制流是现代 Web 开发的核心能力,掌握这些案例能应对 大文件处理、实时多媒体、跨平台数据通信 等复杂场景。
注意事项
最佳实践
- 零拷贝优先:
subarray()
、Transferable、Streams BYOB - slice vs subarray:前者拷贝,后者共享
- Blob URL 及时释放:
URL.revokeObjectURL()
- 端序明确:使用
DataView
控制大小端 - Base64 转换:避免
atob/btoa
,推荐TextEncoder/Decoder
- 大文件处理:用 Streams + Worker,避免阻塞主线程
总结
- 存储容器:
ArrayBuffer
- 视图操作:
TypedArray
、DataView
- 文件处理:
Blob
、FileReader
- 网络支持:
fetch
、WebSocket
、Streams
- 并行与性能:
Transferable
、SharedArrayBuffer
- 高级能力:
WebCrypto
、WebAssembly
通过这些 API,前端能够像后端一样高效、低成本地处理二进制数据,从而支持文件上传下载、实时音视频、加密、甚至操作系统级的应用。