Skip to content

前端玩转Blob、Base64、ArrayBuffer

Published:

概念介绍

Blob

Blob( Binary large object)表示二进制类型的大对象。在数据库管理系统中,将二进制数据存储为一个单一个体的集合。

JavaScript中, Blob 对象表示一个不可变、原始数据的类文件对象。

为了更直观的感受 Blob 对象,我们先来使用 Blob 构造函数,创建一个 Blob 实例,具体如下图所示: 49hHQe

该 Blob 实例含有两个属性:size 和 type。其中 size 属性用于表示数据的大小(以字节为单位),type 是 MIME 类型的字符串。

File

文件(File)接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。

通常情况下, File 对象是来自用户在一个 <input type="file" /> 元素上选择文件后返回的 FileList 对象,也可以是来自由拖放操作生成的 DataTransfer 对象。

File 对象是特殊类型的 BlobFile 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。

Base64

Base64 是一组相似的二进制到文本(binary-to-text)的编码规则,使得二进制数据在解释成 radix-64 的表现形式后能够用 ASCII 字符串的格式表示出来。

在 JavaScript 中,有两个函数被分别用来处理解码和编码 base64 字符串:

atob() 函数能够解码通过base-64编码的字符串数据。相反地,btoa() 函数能够从二进制数据“字符串”创建一个base-64编码的ASCII字符串。

atob()btoa() 均使用字符串。

每一个Base64字符实际上代表着6比特位。因此,3字节(一字节是8比特,3字节也就是24比特)的字符串/二进制文件可以转换成4个Base64字符(4x6 = 24比特)。

这意味着Base64格式的字符串或文件的尺寸约是原始尺寸的133%(增加了大约33%)。如果编码的数据很少,增加的比例可能会更高。

Data URLs

Data URLs,即前缀为 data: 协议的URL,其允许内容创建者向文档中嵌入小文件。

Data URLs 由四个部分组成:前缀(data:)、指示数据类型的MIME类型、如果非文本则为可选的base64标记、数据本身:

data:[<mediatype>][;base64],<data>

mediatype 是个 MIME 类型的字符串,例如 image/jpeg 表示 JPEG 图像文件。如果被省略,则默认值为 text/plain;charset=US-ASCII 如果数据是文本类型,你可以直接将文本嵌入 (根据文档类型,使用合适的实体字符或转义字符)。如果是二进制数据,你可以将数据进行base64编码之后再进行嵌入。

下面是一些示例:

Data URL 可以直接插入 html 某些标签的 src 属性,进行预览。比如 img 和 audio 等。 Blob 和 File 对象则可以通过 URL.createObjectURL(),创建一个临时链接,实现预览。

ArrayBuffer、TypedArray、DataView

ArrayBuffer对象、TypedArray视图和DataView视图是 JavaScript 操作二进制数据的一个接口。

二进制数组由三类对象组成。

(1)ArrayBuffer对象:代表内存之中的一段二进制数据,可以通过“视图”进行操作。“视图”部署了数组接口,这意味着,可以用数组的方法操作内存。

(2)TypedArray视图:共包括 9 种类型的视图,比如Uint8Array(无符号 8 位整数)数组视图, Int16Array(16 位整数)数组视图, Float32Array(32 位浮点数)数组视图等等。

(3)DataView视图:可以自定义复合格式的视图,比如第一个字节是 Uint8(无符号 8 位整数)、第二、三个字节是 Int16(16 位整数)、第四个字节开始是 Float32(32 位浮点数)等等,此外还可以自定义字节序。

简单说,ArrayBuffer对象代表原始的二进制数据,TypedArray视图用来读写简单类型的二进制数据,DataView视图用来读写复杂类型的二进制数据。

类型之间互转

Base64 与 Blob 互转

Base64 —> Blob

// 小红点base64供使用测试
const contentType = "image/png";
const b64Data =
  "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
function b64toBlob(b64Data, contentType = "", sliceSize = 512) {
  // 先将base64数据解码为字符串
  const byteCharacters = atob(b64Data);
  const byteArrays = [];

  // byteCharacters 可能很大,为了性能,可以按 512 拆分处理,最后再合起来。
  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
    const slice = byteCharacters.slice(offset, offset + sliceSize);

    // 创建一个数组,填充每个位字符的 Unicode 码点
    const byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }
    // 生成Uint8Array
    const byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }

  const blob = new Blob(byteArrays, { type: contentType });
  return blob;
}

以上这种方式其实是通过字符串的 charCodeAt 方法来生成 Uint8Array的。

实际上还有一种简便的方法,就是利用 Data URLs 和 fetch

利用浏览器的 fetch api,向 DataURL 发起请求,再利用返回的 Response 对象进行转化。代码如下:

async function b64toBlob(b64Data, contentType = "") {
  const url = `data:${contentType};base64,${b64Data}`;
  const res = await fetch(url);
  return res.blob(); // 同理也可以 res.arrayBuffer() 返回 ArrayBuffer
}

Blob —> Base64

BlobBase64 可以利用浏览器提供的 FileReader 对象。FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 FileBlob 对象指定要读取的文件或数据。

function blobToDataURL(blob) {
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.onload = function (e) {
      resolve(e.target.result);
    };
    reader.readAsDataURL(blob); // 这里是DataURL 如果需要纯base64的话需要自己取
  });
}

ArrayBuffer 与 Blob 互转

ArrayBuffer —> Blob

这个转换比较简单,Blob 构造函数支持直接传染一个 ArrayBuffer

const ab = new ArrayBuffer(32);
const blob = new Blob([ab]); // 注意必须包裹[]

Blob —> ArrayBuffer

使用 Blob.arrayBuffer(),可以返回一个promise且包含blob所有内容的二进制格式的 ArrayBuffer。

代码用法如下。

const blob = new Blob(['hello world'], { type: 'text/plain'});

blob.arrayBuffer().then(buffer => /* 处理 ArrayBuffer 数据的代码……*/);

其实还有另外一个方法,利用浏览器提供的 FileReader 对象,来看看代码。

function blobToArrayBuffer(blob) {
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.onload = function (e) {
      resolve(e.target.result);
    };
    reader.readAsArrayBuffer(blob);
  });
}

ArrayBuffer 与 Base64 互转

base64 —> ArrayBuffer

其实这里与 base64Blob 的方式有点像,不同的地方是直接用 Unit8Array 转换成 ArrayBuffer

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;
}

另外一种方法使用 fetch 的上面已经提供,不再赘述。

ArrayBuffer —> base64

利用 String.fromCharCode 方法,将码点转换成字符串,再利用 btoa()

function arrayBufferToBase64(buffer) {
  const str = String.fromCharCode(...new Uint8Array(arrayBuffer));
  return btoa(str);
}

参考文档

  1. 阮一峰ES6
  2. MDN