本指南全面解析 JavaScript/Node.js 中的二进制数据处理,涵盖 ArrayBuffer、TypedArray、Blob、Base64 等核心概念
传输层: JSON/FormData (组织数据,使用MIME)
↑
格式化层: Base64/Hex (嵌入二进制到文本)
↑
内存层: Blob → ArrayBuffer → TypedArray/Uint8Array (处理二进制)
// 用File API读取成Blob,再转ArrayBuffer/Uint8Array处理字节。
↑
编码层: UTF-8/ASCII (文本) + MIME (类型描述)
↑
底层: 二进制比特流
二进制数据基础概念
Binary?
什么是二进制数据?
- 本质 :计算机存储和处理的基本单位,由 0 和 1 组成
- 在内存中 :以字节(byte)为单位组织,1 字节 = 8 位(bit)
- 在 JavaScript 中 :传统上难以直接操作,ES6 引入了专门的 API
为什么需要处理二进制数据?
| 场景 | 说明 |
|---|---|
| 文件操作 | 读写图片、PDF、视频等二进制文件 |
| 网络请求 | 处理 API 返回的二进制数据(如图片、文件下载) |
| 加密解密 | 密钥、哈希值等都是二进制数据 |
| 音视频处理 | WebRTC、Web Audio API 等需要处理原始音频/视频帧 |
| 与原生模块交互 | Electron 中调用 C++ 插件(.node 文件) |
ASCII:基础字符编码
- 关系:所有文本编码的基础
- 在文件处理中的角色:
-
- 文本文件的基本表示
- Base64编码的输出格式
- HTTP头部的编码基础
UTF-8
一种更现代、更通用的字符编码,它兼容 ASCII,但能使用 1 到 4 个字节来表示世界上几乎所有语言的字符。你可以把它看作是一个巨大的“字典”,不仅包含所有 ASCII 字符,还包含了中文、日文、阿拉伯语等各种语言的字符。
- 定义:变长Unicode编码方案,使用1-4字节表示字符。兼容ASCII(前128字符用1字节)。
- 特点:Web默认文本编码,JSON/FormData的文本部分通常基于UTF-8
- 区别:
ASCII 是 UTF-8 的子集。所有 ASCII 字符在 UTF-8 中都有对应的表示,并且编码方式完全一样。因此,一个纯英文的 UTF-8 文本和 ASCII 文本是完全相同的。但 UTF-8 可以表示更多的字符,而 ASCII 不能。
Base64
二进制→文本(ASCII),用于嵌入、传输
Base64 编码原理
- 作用: 一种 编码算法 。它的唯一目的就是把 任意二进制数据 (比如一张图片、一个视频文件)安全地转换成一串 纯文本(64字符串ASCII) 。
-
- 基于ASCII(输出为ASCII字符)
- 使JSON能传输二进制数据
- 为什么需要?
-
- 因为早期的网络协议或某些纯文本格式(比如 JSON)无法直接处理或传输原始的二进制数据。
- Base64 就像一个“安全包装”,把文件内容打包成一种特殊形式的文本,确保它能在纯文本环境中不被破坏地传输。
Base64 在 JavaScript 中的使用
编码
// 字符串 → Base64
btoa('Hello'); // "SGVsbG8="
// 二进制 → Base64 (关键!)
function arrayBufferToBase64(buffer) {
let binary = '';
const bytes = new Uint8Array(buffer);
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
解码
// Base64 → 字符串
atob('SGVsbG8='); // "Hello"
// Base64 → 二进制
function base64ToArrayBuffer(base64) {
const binaryString = atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
MIME:内容类型标识
- 关系:
-
- 定义了Content-Type(如application/json)
- 为JSON和FormData提供上下文
ArrayBuffer:内存缓冲区
什么是 ArrayBuffer?
- 定义 :表示一段 原始的二进制数据缓冲区 (raw binary data buffer)
- 特点 :
-
- 代表一块 固定大小 的内存区域
- 不能直接操作 内容(没有索引访问等方法)
- 只是一个"容器",需要配合 TypedArray 使用
数据源 (网络/文件/计算)
↓
内存分配 (new ArrayBuffer)
↓
原始内存块 (二进制数据)
↓
ArrayBuffer (内存引用)
- 创建方式 :
const buffer = new ArrayBuffer(8); // 创建 8 字节的缓冲区
console.log(buffer.byteLength); // 8
ArrayBuffer 的本质
想象 ArrayBuffer 是一块 没有门的仓库 :
- 你知道仓库大小(byteLength)
- 但无法直接进入仓库取/放物品
- 需要"工人"(TypedArray)来操作里面的内容
ArrayBuffer 的局限性
const buffer = new ArrayBuffer(4);
// ❌ 无法直接操作
buffer[0] = 255; // 无效操作,不会报错但也不生效
console.log(buffer[0]); // undefined
从网络获取 ArrayBuffer
// 从网络请求获取
fetch('image.png')
.then(response => response.arrayBuffer())
.then(buffer => {
console.log('Image buffer:', buffer);
// buffer 是 ArrayBuffer 对象
});
// 从 Blob 转换
const blob = new Blob(['Hello']);
const buffer = await blob.arrayBuffer(); // ArrayBuffer
TypedArray:类型化数组
为什么需要 TypedArray?
ArrayBuffer 无法直接操作,TypedArray 提供了 访问 ArrayBuffer 的视图 :
- 像给仓库装上门和货架标签
- 规定如何解读内存中的字节
- 提供索引访问和操作方法
常见 TypedArray 类型
| 类型 | 每个元素大小 | 有符号 | 用途 |
|---|---|---|---|
Int8Array | 1 字节 | ✅ | 小整数 |
Uint8Array | 1 字节 | ❌ | 最常用,通用二进制数据 |
Int16Array | 2 字节 | ✅ | 中等整数 |
Uint16Array | 2 字节 | ❌ | Unicode 文本(UTF-16) |
Int32Array | 4 字节 | ✅ | 大整数 |
Uint32Array | 4 字节 | ❌ | 位操作、颜色值 |
Float32Array | 4 字节 | ✅ | 3D 图形、科学计算 |
Float64Array | 8 字节 | ✅ | 高精度计算 |
Uint8Array:二进制处理的核心
为什么 Uint8Array 如此重要?
- 1:1 对应字节 :每个元素 = 1 字节(8 位)
- 文件系统基础 :所有文件在磁盘上都是字节序列
- 网络传输单位 :TCP/IP 协议处理字节流
- 通用性 :可以表示任何二进制数据(图片、PDF、视频等)
文本 (抽象概念)
↓
UTF-8 编码规则 (TextEncoder)
↓
字节序列 (原始数据)
↓
Uint8Array (存储容器)
Uint8Array 示例
// 1、创建 Uint8Array
const uint8 = new Uint8Array(4); // 4 字节,初始化为 [0, 0, 0, 0]
// 2、操作数据
uint8[0] = 72; // 'H' 的 ASCII 值
uint8[1] = 101; // 'e'
uint8[2] = 108; // 'l'
uint8[3] = 108; // 'l'
// 3、转换为字符串(仅当数据是文本时)
const text = String.fromCharCode(...uint8);
console.log(text); // "Hell"
// 重要:Uint8Array 本身是二进制,不是字符串!
console.log(typeof uint8); // "object"
TypedArray 的核心特性
共享内存
多个 TypedArray 可以 共享同一块 ArrayBuffer :
const buffer = new ArrayBuffer(8);
const int32View = new Int32Array(buffer); // 2 个 32 位整数
const uint8View = new Uint8Array(buffer); // 8 个 8 位整数
int32View[0] = 0x12345678;
console.log(uint8View); // [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0] (小端序)
视图偏移
可以从 ArrayBuffer 的任意位置创建视图:
const buffer = new ArrayBuffer(8);
const view1 = new Uint8Array(buffer, 0, 4); // 前 4 字节
const view2 = new Uint8Array(buffer, 4, 4); // 后 4 字节
常用方法
const uint8 = new Uint8Array([1, 2, 3, 4]);
// slice() - 创建副本
const copy = uint8.slice(1, 3); // [2, 3]
// set() - 复制数据
const target = new Uint8Array(6);
target.set([5, 6], 2); // [0, 0, 5, 6, 0, 0]
// subarray() - 创建子视图(共享内存)
const sub = uint8.subarray(1, 3); // [2, 3] (修改会影响原数组)
TypedArray 与普通数组的区别
| 特性 | TypedArray | 普通数组 |
|---|---|---|
| 长度 | 固定 | 可变 |
| 类型 | 单一类型 | 任意类型 |
| 性能 | ⚡ 高(连续内存) | 🐢 较低 |
| 方法 | 有限(slice, set, subarray) | 丰富(map, filter, reduce) |
| 内存 | 连续分配 | 可能不连续 |
💡 ****重要提示 :TypedArray 不是 Array 的子类! Array.isArray(uint8Array) 返回 false 。
Blob:浏览器二进制对象
什么是 Blob?
- 定义:JavaScript对象,不可变的原始二进制数据对象(Binary Large Object)
- 特点:
-
- 有
size和type(MIME 类型)属性 - 用于前端文件操作的标准接口, 是浏览器中表示二进制数据的标准方式
- 不可变性:Blob 一旦创建,内容就不能修改
- 设计目的:安全地表示二进制数据(如文件)
- 安全考虑:防止意外修改原始文件内容
- 有
- 创建方式 :
// 从字符串创建
const textBlob = new Blob(['Hello, world!'], { type: 'text/plain' });
// 从 TypedArray 创建
const uint8 = new Uint8Array([72, 101, 108, 108, 111]);
const binaryBlob = new Blob([uint8], { type: 'application/octet-stream' });
blob的作用
原始数据 --> File --> Blob
|
|--> [转为 ArrayBuffer]
| |
| |--> [Uint8Array] --> [修改]
| |
| |--> [Base64] --> [嵌入 JSON]
|
|--> [直接] --> [FormData] --> [传输]
|
|--> [URL.createObjectURL] --> [显示]
Blob 的核心方法
📥 获取数据
| 方法 | 作用 | 返回类型 |
|---|---|---|
arrayBuffer() | 转为 ArrayBuffer | Promise |
text() | 转为字符串 | Promise |
stream() | 获取 ReadableStream | ReadableStream |
// 使用示例
const blob = new Blob(['Hello']);
const buffer = await blob.arrayBuffer(); // ArrayBuffer
const text = await blob.text(); // "Hello"