JavaScript二进制数据序列化和反序列化

news/2024/7/7 13:20:24 标签: javascript, json, 操作系统

最近业余时间在搞h5小游戏,由于同步协议过于频繁,和服务器之间的同步直接用json就显得太浪费了,于是我们商讨之下决定改用二进制。学习过程中并没有遇到一篇就解决问题的文章,遂再总结一发。

 

1.二进制数据的存储

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

(1)ArrayBuffer对象:代表内存之中的一段二进制数据,它不能直接读写,只能通过视图(TypedArray视图和DataView视图)来读写,视图的作用是以指定格式解读二进制数据。

(2) TypedArray对象:ArrayBuffer对象作为内存区域,可以存放多种类型的数据。同一段内存,不同数据有不同的解读方式,这就叫做“视图”(view)。ArrayBuffer有两种视图,一种是TypedArray视图,另一种是DataView视图,两者的区别主要是字节序,前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型。

(3)DataView对象:用来生成内存的视图,可以自定义格式和字节序,比如第一个字节是Uint8(无符号8位整数)、第二个字节是Int16(16位整数)、第三个字节是Float32(32位浮点数)等等。

 

2.把数据写入二进制数组

例如写入4个int

var buffer = new ArrayBuffer(16);
var int32View = new Int32Array(buffer);

for (var i = 0; i < int32View.length; i++) {
  int32View[i] = i * 2;
}

上面代码生成一个16字节的ArrayBuffer对象,然后在它的基础上,建立了一个32位整数的视图。由于每个32位整数占据4个字节,所以一共可以写入4个整数,依次为0,2,4,6。

 

3.大端小端的问题

目前,所有个人电脑几乎都是小端字节序,所以TypedArray数组内部也采用小端字节序读写数据,或者更准确的说,按照本机操作系统设定的字节序读写数据。

这并不意味大端字节序不重要,事实上,很多网络设备和特定的操作系统采用的是大端字节序。

js提供了设置大端和小端的函数,只需要在读取或写入时表明即可。dv代表一个ArrayBuffer数组。

例子:

// 小端字节序
var v1 = dv.getUint16(1, true);

// 大端字节序
var v2 = dv.getUint16(3, false);

// 大端字节序
var v3 = dv.getUint16(3);

// 在第1个字节,以大端字节序写入值为25的32位整数
dv.setInt32(0, 25, false);

// 在第5个字节,以大端字节序写入值为25的32位整数
dv.setInt32(4, 25);

// 在第9个字节,以小端字节序写入值为2.5的32位浮点数
dv.setFloat32(8, 2.5, true);

false或者undefined表示使用大端字节序写入,true表示使用小端字节序写入。

 

4.将二进制数组专为字符串

这里其实被坑了挺久的,我们的协议传输之前使用的是JSON.stringify(data)把数据转成json串进行传输,现在需要的数据格式是类似下面这种:

{uid:100, controlData: byteInfo} 其中byteInfo是我们之前写好的ArrayBuffer,本来以为大功告成,谁知json并不支持二进制数组的数据,转过之后会无法解析,所以我们还需要把刚才的二进制数据转为字符串:

// ArrayBuffer转为字符串,参数为ArrayBuffer对象
function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint16Array(buf));
}

// 字符串转为ArrayBuffer对象,参数为字符串
function str2ab(str) {
  var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
  var bufView = new Uint16Array(buf);
  for (var i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}

5.为了在转json的时候保证不出问题,最后我们又用了base64,把非ascii字符统一转为ascii字符

例如:

var encodedData = window.btoa("Hello, world"); // encode a string
var decodedData = window.atob(encodedData); // decode the string

终于大功告成,一个小小的数据经过几番折腾终于变成了一个可以传输的、奇怪的字符串。和服务器调了一发,完美解析

 

 

参考资料:

http://javascript.ruanyifeng.com/stdlib/arraybuffer.html 理论基础,强烈推荐

https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/atob  base64文档

http://noyesno.net/page/javascript/binary.html

http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers/

 

转载于:https://www.cnblogs.com/SolarWings/p/6262932.html


http://www.niftyadmin.cn/n/1112744.html

相关文章

网页中meta标记

网页中常常看见有这样的标记&#xff0c;他们是清浏览器缓存用的 <meta http-equiv"Pragma" content"no-cache"><meta http-equiv"Cache-Control" content"no-cache"><meta http-equiv"Expires" content&q…

补充(echo用法、for循环、continue、break、IFS字段分隔符)

文章目录echo用法for循环breakcontinueIFS字段分隔符echo用法 echo -n 表示不换行输出 echo -e 输出转义字符&#xff0c;将转义后的内容输出到屏幕上 常用的转义字符 \b&#xff1a;转义后相当于按退格键&#xff08;backspace&#xff09;&#xff0c;但前提是"\b&qu…

腾讯云独家详解小程序多人视频通话

欢迎大家前往云社区&#xff0c;获取更多腾讯海量技术实践干货哦~作者&#xff1a;小程序音视频产品经理功能体验 在微信小程序中搜索 腾讯视频云 可以加载到我们的演示用小程序&#xff0c;其中 多人音视频 功能可用于体验和测试多人音视频通话功能。出于 UI 美观和画面大小的…

Linux文件及目录的Suid/Guid和T属性(转)

Linux文件及目录的Suid/Guid和T属性(转)[more]  1. 4000---调整用户号 2000---调整组号 1000---粘着置位 2. suid/guid程序 当一个程序的用户或组被置位的时候&#xff0c;即4000或2000时&#xff0c;可实现某些特殊的功能一般来说&#xff0c;一个运行中的程序为运行这个程序…

用循环语句完成简单图案组成——一篇就够了!!!

文章目录九九乘法表for循环while循环成品直角三角形代码成品等腰三角形代码成品菱形代码成品长方形代码成品平行四边形代码成品梯形代码成品九九乘法表 for循环 while循环 成品 直角三角形 代码 成品 等腰三角形 代码 成品 菱形 代码 1 #!/bin/bash2 for ((i1;i<10;i))3…

JavaScript异步基础

唯一比不知道代码为什么崩溃更可怕的事情是&#xff0c;不知道为什么一开始它是工作的&#xff01;在 ECMA 规范的最近几次版本里不断有新成员加入&#xff0c;尤其在处理异步的问题上&#xff0c;更是不断推陈出新。然而&#xff0c;我们在享受便利的同时&#xff0c;也应该了…

TCSH shell变量和特征配置(转)

TCSH shell变量和特征配置(转)[more]TCSHshell可以使用户使用shell配置变量和特征配置自己的shell.也可以使用set命令设置特征.TCSH也有注册,注消以及何时进入TCSHshell的配置文件.一、TCSH shell 特征TCSH有几个特征,允许控制不同的shell操作的方法.TCSH shell特征不仅包括许多…

BAK文件怎么恢复到数据库中

1.右击SQLServer2000实例下的“数据库”文件夹。就是master等数据库上一级的那个图标。选择“所有任务”,“还原数据库” 2.在“还原为数据库”中填上你希望恢复的数据库名字。这个名字应该与你的源码中使用的数据库名字一致。 3.在弹出的对话框中&#xff0c;选“从设备” 4.点…