zoukankan      html  css  js  c++  java
  • JavaScript二进制数据序列化和反序列化

    最近业余时间在搞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/

     

  • 相关阅读:
    让SVN自动更新代码注释中的版本号
    eclipse 查看jdk的源代码
    Java Abstract class and Interface
    Eclipse在保存的时间格式化
    Java中使用Runtime和Process类运行外部程序
    免费的东西:火箭的社会图标
    最土团购程序一些常见的数据库操作
    PostgreSQL在何处处理 sql查询之四十五
    遇到 dereferencing pointer to incomplete type 该怎么办
    PostgreSQL在何处处理 sql查询之四十四
  • 原文地址:https://www.cnblogs.com/SolarWings/p/6262932.html
Copyright © 2011-2022 走看看