WHAT - 最常用的 base64 数据编码方式(含 Blob 和 ArrayBuffer)

一、介绍

Base64 是一种数据编码方式,用于将二进制数据转换为可打印的 ASCII 字符串。这种编码方式广泛用于在文本系统中传输二进制数据,比如在电子邮件中嵌入图像,或者在网络协议中传输复杂的数据。

// 123456
// 编码后
// MTIzNDU2

//hello
//编码后
//aGVsbG8=

1. Base64 的工作原理

Base64 字符集

Base64 字符集是一种用于将二进制数据编码为可打印的 ASCII 字符串的标准字符集。它包含 64 个字符,这些字符包括字母、数字以及两个特殊字符(通常是 +/,在 URL 和文件系统中有时会用不同的字符,如 -_)。

Base64 字符集的字符分布如下:

  1. 大写字母(A-Z):A 到 Z,代表值 0 到 25。
  2. 小写字母(a-z):a 到 z,代表值 26 到 51。
  3. 数字(0-9):0 到 9,代表值 52 到 61。
  4. 特殊字符:+ 代表值 62。/ 代表值 63。

这些字符用于表示 6 位二进制数。具体的字符集如下(在大多数 Base64 实现中):

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

Base64 编码基本原理

Base64 编码将每 3 个字节的原始二进制数据转换为 4 个可打印字符。

这是因为每个 Base64 字符表示 6 位数据(2^6 = 64),即 000000~111111,代表0~63,而 3 个字节是 24 位(3*8 = 24)。将 24 位数据分成 4 组,每组 6 位,从而产生 4 个 Base64 字符。

  • 原始数据:每 3 个字节 = 24 位。
  • Base64 编码:每 4 个字符 = 24 位。

Base64 编码具体解释

让我们更详细地解释一下 Base64 编码的过程,特别是为什么 3 个字节的二进制数据会转换为 4 个 Base64 字符。

  1. 字节与位的关系

    • 1 字节 = 8 位(bits)。
    • 3 个字节 = 3 * 8 = 24 位。
  2. Base64 字符表示

    • Base64 编码将二进制数据分成 6 位一组进行处理,因为 Base64 字符集包含 64 个不同的字符(2^6 = 64)。所以,每个 Base64 字符表示 6 位数据。
  3. 编码过程

    • 步骤 1: 从 3 个字节的二进制数据中提取 24 位数据。

    • 步骤 2: 将这 24 位数据分成 4 组,每组 6 位。

    • 步骤 3: 每 6 位数据通过 Base64 编码表(包含 64 个字符)映射成一个 Base64 字符。这就是为什么 3 个字节会被编码为 4 个 Base64 字符。

2. Base64 的编码示例

假设我们要编码字符串 “hello”:

  1. 原始数据

    • “hello” 的 ASCII 编码是 104 101 108 108 111
  2. 转换为二进制

    • 104 = 01101000
    • 101 = 01100101
    • 108 = 01101100
    • 108 = 01101100
    • 111 = 01101111
  3. 分组

    • 每 6 位分成一组,例如:
      011010 000110 010101 101100 011011 001111
      
  4. 编码

    • 这些 6 位组对应 Base64 字符,例如:
      011010 = 26 = a
      000110 = 6 = G
      010101 = 21 = V
      101100 = 44 = s
      011011 = 27 = b
      001111 = 15 = P
      
    • 最终编码结果是 “aGVsbG8=”。

注意:Base64 编码的结果可能会在末尾添加一个或两个 = 符号作为填充字符,用于确保数据长度是 4 的倍数。

3. Base64 的应用

下面是针对不同场景的 Base64 编码和解码示例,包括 URL 嵌入、电子邮件附件、数据传输和存储与缓存。我们将使用 JavaScript 代码来演示这些操作。

3.1 在 URL 中嵌入数据

场景描述:将图像数据通过 Base64 编码嵌入到 URL 中,例如用作 src 属性的值。

代码示例

假设我们有一个小的 PNG 图像文件,我们将其转为 Base64 字符串,然后在 HTML 中使用 Data URL 进行嵌入。

// 图像数据转换为 Base64 字符串的示例
function encodeImageToBase64(imageFile) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(imageFile);
  });
}

// 假设 imageFile 是 File 对象,例如通过 file input 获取的图像文件
const imageFile = document.querySelector('input[type="file"]').files[0];

encodeImageToBase64(imageFile).then(base64String => {
  console.log(base64String); // 输出 Base64 编码字符串
  // 使用 Base64 字符串作为图像的 src
  document.querySelector('img').src = base64String;
});

Base64 字符串示例

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAAC8GO2jAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHwAAAABJRU5ErkJggg==

3.2 电子邮件附件

场景描述:在电子邮件中嵌入图像或文档附件,Base64 编码用于将二进制数据嵌入邮件内容。

代码示例

// 将文件转换为 Base64 字符串
function convertFileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

// 假设 file 是要发送的文件,例如通过 file input 获取的文件
const file = document.querySelector('input[type="file"]').files[0];

convertFileToBase64(file).then(base64String => {
  // 在邮件中嵌入 Base64 数据
  const emailBody = `<img src="${base64String}" alt="Embedded Image">`;
  console.log(emailBody); // 输出邮件内容,通常由邮件客户端进行发送
});

Base64 字符串示例

data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAAAAAAAD/2wBDAAoHBwkHBgoJCAkLCwoMDxkQDw4ODxwQEBwTGBYWFx0dIyIoIyIiIyIhJi4kIyIoNjo2LCYgJSYlLCYsMTExLCsyLC4vJjAqMygyNjo2N0FfJSMfFjM1M0YwYTMzLV0uMz5iFfAvfFwmMfJwNWUuLzP/2wBDAQsLC8rLC8wLjQ4MzUyMj8vM2QwP0PCZFBZXk5eXF9fX13lHUkLAw8xPD5dZHiMmYPk9fXYnKk2YJLc6MMPS9eK0YXEro6XjptH5ae/f1sZYqFjpLgWCyMuJUdFCOMqKIlC5Ti8gHjK0ePoNBe8aFSih+KTcCnEEw3zXyRYmrDmfMTlI6MYDFX/l5Y5r/mWq2Bf8XBLZfD4uYl2ziFthP6oyW8Onxw5WzNGxkL77B4u3D0+4ys...

3.3 数据传输

场景描述:通过 API 或网络协议将二进制数据转换为 Base64 字符串并进行传输。

代码示例

// 将二进制数据编码为 Base64 字符串
function arrayBufferToBase64(arrayBuffer) {
  let binary = '';
  let bytes = new Uint8Array(arrayBuffer);
  let len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary);
}

// 假设我们从 API 获取到的二进制数据
fetch('https://example.com/api/data')
  .then(response => response.arrayBuffer())
  .then(arrayBuffer => {
    const base64String = arrayBufferToBase64(arrayBuffer);
    console.log(base64String); // 输出 Base64 编码字符串
    // 将 Base64 字符串发送到服务器或其他应用
  });

Base64 字符串示例

iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAAC8GO2jAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHwAAAABJRU5ErkJggg==

延伸

让我们详细解释一下为什么对从 API 获取的二进制数据进行上述格式转换:

  1. 从 API 获取响应数据

当你使用 fetch API 请求数据时,响应可以是多种格式,包括文本、JSON、BlobArrayBuffer 等。fetch 的默认响应格式是 ReadableStream,需要进一步处理来获取具体的数据格式。对于二进制数据,response.arrayBuffer() 是一种常见的选择。

  1. 转换为 ArrayBuffer

ArrayBuffer 是一种通用的、固定长度的原始二进制数据缓冲区。在 Web API 中,response.arrayBuffer() 方法将响应的原始数据转换为 ArrayBuffer 对象,这样可以更方便地处理二进制数据。

fetch('https://example.com/api/data')
  .then(response => response.arrayBuffer())
  .then(arrayBuffer => {
    // arrayBuffer 现在是原始的二进制数据
  });

注意,BlobArrayBuffer 都是 Web API 中用于处理二进制数据的两种重要数据结构,它们各自具有不同的用途和特性。主要区别在于:

  • 数据处理方式:ArrayBuffer 用于低级别的二进制数据处理,依赖视图(如 Uint8Array)来访问数据。Blob 用于高层次的数据处理,支持文件和流式操作。
  • 数据大小:ArrayBuffer 适用于处理固定大小的二进制数据。Blob 适用于处理任意大小的二进制数据块,可以是非常大的数据。
  • 数据用途:ArrayBuffer 通常用于处理来自网络请求的二进制数据,适合数据转换和操作。Blob 通常用于处理文件上传、下载和生成内容,适合文件和流的操作。
  1. ArrayBuffer 转换为 Base64 字符串

ArrayBuffer 本身是二进制的,而 Base64 是一种文本编码方式,用于将二进制数据转换为字符串格式。Base64 编码的好处包括:

  • 可嵌入文本环境:Base64 编码的字符串可以在 HTML、JSON、XML 等文本格式中嵌入和传输。
  • 数据传输:在某些协议或服务中,Base64 编码的文本数据更易于处理和传输。

转换步骤

function arrayBufferToBase64(arrayBuffer) {
  let binary = '';
  let bytes = new Uint8Array(arrayBuffer);
  let len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary);
}
  1. ArrayBuffer 转 Uint8Arraynew Uint8Array(arrayBuffer)
    • Uint8Array 是一种视图,它允许我们以字节为单位访问 ArrayBuffer 的数据。

请添加图片描述

  1. Uint8Array 转 Binary StringString.fromCharCode()
    • Uint8Array 的每个字节转换为字符,并将这些字符组合成一个二进制字符串。因为 btoa 要求入参是二进制字符串。

请添加图片描述

  1. Binary String 转 Base64window.btoa()
    • 使用 window.btoa() 方法将二进制字符串转换为 Base64 编码的字符串。
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAADZ+foAAAAJcEhZcwAACxMAAAsTAdjz8gAAAHSiVHBtSFiaL3diNS1zYWUtYm5vODYAAAAyAAAAYAAAAPbAAAAASUVORK5CYII='

总结,每一步的转换都有其特定的用途:

  • ArrayBuffer 提供了对原始二进制数据的访问。
  • Uint8Array 使我们可以以字节为单位处理数据。
  • Binary String 是一种在 JavaScript 中处理二进制数据的中间格式。
  • Base64 编码将二进制数据转换为可嵌入文本环境中的字符串格式,便于传输和存储。

这些转换步骤确保了我们能够有效地处理和传输 API 返回的二进制数据,并将其转换为可以在不同场景中使用的格式。

3.4 存储与缓存

场景描述:将二进制数据(如图像)编码为 Base64 字符串并存储在浏览器的本地存储中。

代码示例

// 将图像数据存储到本地存储
function storeImageInLocalStorage(imageFile) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => {
      const base64String = reader.result;
      localStorage.setItem('storedImage', base64String);
      resolve();
    };
    reader.onerror = reject;
    reader.readAsDataURL(imageFile);
  });
}

// 从本地存储中读取图像数据并显示
function displayStoredImage() {
  const base64String = localStorage.getItem('storedImage');
  if (base64String) {
    document.querySelector('img').src = base64String;
  }
}

// 假设 imageFile 是 File 对象,例如通过 file input 获取的图像文件
const imageFile = document.querySelector('input[type="file"]').files[0];

storeImageInLocalStorage(imageFile).then(() => {
  displayStoredImage();
});

Base64 字符串示例(存储在本地存储中):

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAAC8GO2jAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHwAAAABJRU5ErkJggg==

总结

这些示例展示了如何在不同场景中使用 Base64 编码进行数据转换和处理:

  1. URL 中嵌入数据:将 Base64 编码的数据直接嵌入到 URL 中,如图像的 src 属性。
  2. 电子邮件附件:将二进制文件(如图像或文档)编码为 Base64 字符串,然后在电子邮件中嵌入。
  3. 数据传输:将二进制数据编码为 Base64 字符串,通过 API 或网络协议进行传输。
  4. 存储与缓存:将 Base64 编码的数据存储在浏览器的本地存储中,用于后续的读取和显示。

4. 在 JavaScript 中使用 Base64

编码

const str = "hello";
const encoded = btoa(str); // "aGVsbG8="
console.log(encoded);

MDN - btoa

解码

const encoded = "aGVsbG8=";
const decoded = atob(encoded); // "hello"
console.log(decoded);

MDN - atob

使用 Buffer (Node.js)

在 Node.js 中,你可以使用 Buffer 对象来进行 Base64 编码和解码:

// 编码
const buffer = Buffer.from('hello');
const encoded = buffer.toString('base64'); // "aGVsbG8="
console.log(encoded);

// 解码
const decodedBuffer = Buffer.from(encoded, 'base64');
const decoded = decodedBuffer.toString(); // "hello"
console.log(decoded);
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值