技巧 | 03 JavaScript 中将 ArrayBuffer 转换为字符串
00 TextDecoder & ArrayBuffer
在 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),但它们的应用场景和使用方式有所不同。
3.1 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 视图对象。
3.2 Uint32Array 适用于存储任意的 32 位无符号整数类型的数据,每一项占用 4 个字节。可以通过数组下标的方式直接访问和修改其中的数据。
好的,以下是一个使用 Uint32Array 在 JavaScript 中实现求素数的例子:
// 埃拉托斯特尼(Eratosthenes)筛法
function sieveOfEratosthenes(n) {
const primes = new Uint32Array(n + 1).fill(1);
primes[0] = 0;
primes[1] = 0;
for (let i = 2; i <= Math.sqrt(n); i++) {
if (primes[i]) {
for (let j = i * i; j <= n; j += i) {
primes[j] = 0;
return primes;
const n = 100;
const primes = sieveOfEratosthenes(n);