问题

近期有个项目需要通过小程序配置设备,协议通过蓝牙传输裸的数据流,牵涉到js端将ArrayBuffer组装成String。

方法

由于 ArrayBuffer 实际上是一个字节数组,因此这种转换要求两端就如何将 String 中的字符表示为字节达成一致。 您之前可能已经看过这个“协议”:它是字符串的字符编码(通常的“协议条款”是,例如,Unicode UTF-16 和 iso8859-1)。 因此,假设您和对方已就 UTF-16 编码达成一致,则转换代码可能类似于:

function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint16Array(buf));
}
function str2ab(str) {
  var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
  var bufView = new Uint16Array(buf);
  for (var i=0, strLen=str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}

注意:Uint16Array的用法。这是一个ArrayBuffer视图,它将数组缓冲区的字节对齐为16位元素。它本身不处理字符编码,字符编码是由String.fromCharCode和str.charCodeAt作为Unicode处理的。

ArrayBuffers 用于传输原始数据,一些新的 API 依赖于它们,包括 WebSocketsWeb IntentsXMLHttpRequest2WebWorkers。 然而,由于它们最近才被引入 JavaScript 世界,因此有时会被曲解或误用。

从语义上讲,ArrayBuffer 只是通过特定掩码查看的字节数组。 这个掩码是 ArrayBufferView 的一个实例,定义了字节如何对齐以匹配内容的预期结构。 例如,如果您知道 ArrayBuffer 中的字节表示一个 16 位无符号整数数组,您只需将 ArrayBuffer 包装在 Uint16Array 视图中,您就可以使用方括号语法操作其元素,就好像 Uint16Array 是一个整数数组一样:

// suppose buf contains the bytes [0x02, 0x01, 0x03, 0x07]
// notice the multibyte values respect the hardware endianess, which is little-endian in x86
var bufView = new Uint16Array(buf);
if (bufView[0]===258) {   // 258 === 0x0102
  console.log("ok");
}
bufView[0] = 255;    // buf now contains the bytes [0xFF, 0x00, 0x03, 0x07]
bufView[0] = 0xff05; // buf now contains the bytes [0x05, 0xFF, 0x03, 0x07]
bufView[1] = 0x0210; // buf now contains the bytes [0x05, 0xFF, 0x10, 0x02]

使用TextEncoder或TextDecoder

if (!("TextEncoder" in window)) 
  alert("Sorry, this browser does not support TextEncoder...");

var enc = new TextEncoder(); // always utf-8
console.log(enc.encode("This is a string converted to a Uint8Array"));

TextDecoder 接口代表特定方法的解码器,即特定的字符编码,如 utf-8、iso-8859-2、koi8、cp1261、gbk、…解码器将字节流作为输入并发出 码点流。

if (!("TextDecoder" in window))
  alert("Sorry, this browser does not support TextDecoder...");

var enc = new TextDecoder("utf-8");
var arr = new Uint8Array([84,104,105,115,32,105,115,32,97,32,85,105,110,116,
                          56,65,114,114,97,121,32,99,111,110,118,101,114,116,
                          101,100,32,116,111,32,97,32,115,116,114,105,110,103]);
console.log(enc.decode(arr));

参考文章

  1. How to convert ArrayBuffer to and from String
  2. Converting between strings and ArrayBuffers
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐