前端二进制数据---blob、base64、arrayBuffer....

175 阅读7分钟

本指南全面解析 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 类型

类型每个元素大小有符号用途
Int8Array1 字节小整数
Uint8Array1 字节最常用,通用二进制数据
Int16Array2 字节中等整数
Uint16Array2 字节Unicode 文本(UTF-16)
Int32Array4 字节大整数
Uint32Array4 字节位操作、颜色值
Float32Array4 字节3D 图形、科学计算
Float64Array8 字节高精度计算

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()转为 ArrayBufferPromise
text()转为字符串Promise
stream()获取 ReadableStreamReadableStream
// 使用示例
const blob = new Blob(['Hello']);
const buffer = await blob.arrayBuffer(); // ArrayBuffer
const text = await blob.text(); // "Hello"