添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
跳到主要内容

技巧 | 03 JavaScript 中将 ArrayBuffer 转换为字符串

· 阅读需 8 分钟
木易(OwenYang)

在 JavaScript 中将 ArrayBuffer 转换为字符串,可以使用 TextDecoder API。TextDecoder 可从字节序列中解码文本内容,支持多种编码格式。

以下是将 ArrayBuffer 转换为字符串的示例代码:

// 假设 ArrayBuffer 对象为 buffer
const decoder = new TextDecoder('utf-8');
const text = decoder.decode(buffer);

在上面的代码中,我们创建了一个 TextDecoder 对象,使用 utf-8 编码对 ArrayBuffer 进行解码,并将解码后的文本存储在变量 text 中。

如果 ArrayBuffer 中存储的是 GB2312 编码的文本,可以将 utf-8 编码修改为 gb2312

您还可以封装为函数,以便于使用:

function arrayBufferToString(buffer, encoding = 'utf-8') {
const decoder = new TextDecoder(encoding);
return decoder.decode(buffer);
}

这个函数接收两个参数,第一个参数表示要转换的 ArrayBuffer 对象,第二个参数为编码格式(默认为'utf-8')。 返回转换后的字符串。调用该函数的方式如下所示:

const buffer = new ArrayBuffer(2);
const intArray = new Uint8Array(buffer);
intArray[0] = 72;
intArray[1] = 105;

const str = arrayBufferToString(buffer);
console.log(str); // Output: Hi

01 实际问题 - 网页乱码

nodejs 使用 axios 写爬虫时 Response 乱码,经查查发现网页编码是 gb2312 的。则我们可以通过返回 arraybuffer 的方式,再重新编码即可。

const { data } = await axios.get('http://xxx.y.z', { responseType: 'arraybuffer'});

const normalStrig = arrayBufferToString(Buffer.from(data), 'gb2312'); // 返回正确的字符串

02 技术细节 - ArrayBuffer、Int32Array等

ArrayBuffer 是一种用于在 JavaScript 中存储二进制数据的对象,可以看做是一个固定大小的字节缓冲区。可以使用 ArrayBuffer 来存储任意类型的二进制数据,包括数字、图像、音频等等。

Int32Array 是一种类型化数组(TypedArray),它只能存储 32 位 整数类型的数据。具体来说,Int32Array 可以存储范围在 -2147483648 ~ 2147483647 之间的整数数据,也就是 JavaScript 中的 32 位有符号整数类型。

Int32Array 中每一项都占用 4 个字节,使用 Int32Array 对象可以快速地读取和写入 ArrayBuffer 中的 32 位整数数据,适合处理大量数据的场景。

除了 Int32Array,还有一些其他的类型化数组也可以用于存储不同类型的数据,包括:

  • Int8Array:1 个字节的有符号整数类型,范围在 -128 ~ 127 之间;
  • Uint8Array:1 个字节的无符号整数类型,范围在 0 ~ 255 之间;
  • Uint16Array:2 个字节的无符号整数类型,范围在 0 ~ 65535 之间;
  • Int16Array:2 个字节的有符号整数类型,范围在 -32768 ~ 32767 之间;
  • Uint32Array:4 个字节的无符号整数类型,范围在 0 ~ 4294967295 之间;
  • Float32Array:4 个字节的单精度浮点数类型;
  • Float64Array:8 个字节的双精度浮点数类型。
  • 以上这些类型化数组都只能存储指定类型的数据,并且每一项占用的字节数都是固定的。使用类型化数组可以轻松地读取和写入 ArrayBuffer 中指定类型的数据,提高数据读写的效率。

    03 技术举例

    Uint8Array 和 Uint32Array 都是类型化数组(TypedArray),但它们的应用场景和使用方式有所不同。

    Uint8Array 适用于存储任意的 8 位无符号整数类型的数据,每一项占用一个字节。可以通过数组下标的方式直接访问和修改其中的数据。

    以下是 Uint8Array 的一个例子,使用它来将一个字符串编码成 UTF-8 的字节数组:

    function encodeUTF8(str) {
    const codePoints = Array.from(str, c => c.codePointAt(0));
    const buffer = new ArrayBuffer(codePoints.length * 4);
    const uint8Array = new Uint8Array(buffer);
    let offset = 0;
    for (let i = 0; i < codePoints.length; i++) {
    const codePoint = codePoints[i];
    if (codePoint < 0x80) {
    uint8Array[offset++] = codePoint;
    } else if (codePoint < 0x800) {
    uint8Array[offset++] = 0xC0 | (codePoint >> 6);
    uint8Array[offset++] = 0x80 | (codePoint & 0x3F);
    } else if (codePoint < 0x10000) {
    uint8Array[offset++] = 0xE0 | (codePoint >> 12);
    uint8Array[offset++] = 0x80 | ((codePoint >> 6) & 0x3F);
    uint8Array[offset++] = 0x80 | (codePoint & 0x3F);
    } else {
    uint8Array[offset++] = 0xF0 | (codePoint >> 18);
    uint8Array[offset++] = 0x80 | ((codePoint >> 12) & 0x3F);
    uint8Array[offset++] = 0x80 | ((codePoint >> 6) & 0x3F);
    uint8Array[offset++] = 0x80 | (codePoint & 0x3F);
    }
    }
    return uint8Array.subarray(0, offset);
    }

    const str = "Hello, 世界!";
    const byteArr = encodeUTF8(str);
    console.log(byteArr);

    在上面的代码中,我们通过 new Uint8Array(buffer) 创建了一个长度为 codePoints.length * 4 的 Uint8Array 对象 uint8Array ,即总共分配了足够存储 UTF-8 字节数组的缓存空间。然后通过对字符的 Unicode 编码进行判断,将每个字符转换为对应的 UTF-8 字节序列,并存储到 uint8Array 中。最后通过 uint8Array.subarray(0, offset) 返回仅包含有效数据的 Uint8Array 视图对象。

    Uint32Array 适用于存储任意的 32 位无符号整数类型的数据,每一项占用 4 个字节。可以通过数组下标的方式直接访问和修改其中的数据。

    好的,以下是一个使用 Uint32Array 在 JavaScript 中实现求素数的例子: