直接用 DataView 解析二进制文件需先获取 ArrayBuffer,再按字节序和偏移量逐段读取;支持小端/大端解析、动态偏移跳读,但写入需对齐且调试需转 Uint8Array 查看原始字节。

直接用 DataView 解析二进制文件,关键在于把文件转成 ArrayBuffer,再用 DataView 按约定结构逐段读取——它不关心数据“是什么”,只负责告诉你“某几个字节按某种规则解释出来是什么值”。
先拿到原始字节:File 或 fetch → ArrayBuffer
浏览器中解析本地文件,必须走 FileReader.readAsArrayBuffer();如果是网络请求,用 response.arrayBuffer()。这两条路径都跳过字符串解码环节,避免 UTF-8 或其他编码污染原始字节。
- 用户选中 .sbsong 文件后:
const arrayBuffer = await file.arrayBuffer() - 从服务器拉取二进制资源:
fetch('/song.sbsong').then(r => r.arrayBuffer()) - 切忌用
response.text()或FileReader.readAsText()—— 一旦转成字符串,0x00、0xFF 这类字节就可能丢失或被替换
创建 DataView 并控制读取位置
DataView 不自动推进偏移,每次读写都得手动传入 byteOffset(单位是字节)。你可以把它当成一把带刻度的游标卡尺:指到哪,就从那开始量。
- 基础创建:
const dv = new DataView(arrayBuffer)(读取整个 buffer) - 只读中间一段:
const dv = new DataView(arrayBuffer, 4, 12)(从第 4 字节起,读 12 字节) - 读一个 32 位小端整数:
dv.getInt32(0, true);读大端就传false或省略 - 读错了字节序?结果会完全不对——比如 0x01000000 小端读是 1,大端读是 16777216
混合类型 + 动态偏移:典型解析流程
像 .sbsong、BMP、WAV 这类格式,通常开头是固定长度头(含签名、长度),后面跟着变长内容。DataView 的优势就体现在这种“跳着读”的场景里。
- 读前 4 字节签名:
dv.getUint32(0, true)(小端) - 读接下来 2 字节版本号:
dv.getUint16(4, true) - 读第 6 字节起的 ASCII 文本:循环调用
dv.getUint8(offset++),遇到 0x00 或 0x0A 停止 - 遇到字段长度不固定时(如字符串长度由前面一个 uint16 决定),先读长度值,再按该值算出下一段起始 offset
写入与调试注意事项
DataView 同样支持写入,但生产环境多数是解析(读),写入多见于构造协议包或生成测试文件。
- 写入前确认 offset 不越界:
if (offset + 4 > dv.buffer.byteLength) throw new Error('write overflow') - 写入 int32 到 offset=1 会抛 RangeError——getInt32 要求 offset 是 4 的倍数,这是硬性对齐限制
- 调试时别直接
console.log(dv),它不输出内容;可用new Uint8Array(dv.buffer)看原始字节序列 - 和 TypedArray 共享同一 buffer:改 DataView 某处,Uint8Array 对应位置也会变,适合联合验证

















