JavaScript前端开发之实现二进制读写操作


Posted in Javascript onNovember 04, 2015

关于javascript前端开发之实现二进制读写操作的相关介绍,请看以下内容详解,本文介绍的非常详细,具有参考价值。

由于种种原因,在浏览器中无法像nodejs那样操作二进制。

最近写了一个在浏览器端操作读写二进制的帮助类

!function (entrance) {
  "use strict";
  if ("object" === typeof exports && "undefined" !== typeof module) {
    module.exports = entrance();
  } else if ("function" === typeof define && define.amd) {
    define([], entrance());
  } else {
    var f;
    if ("undefined" !== typeof window) {
      f = window;
    } else {
      throw new Error('wrong execution environment');
    }
    f.TinyStream = entrance();
  }
}(function () {
  var binaryPot = {
    /**
     * 初始化字节流,把-128至128的区间改为0-256的区间.便于计算
     * @param {Array} array 字节流数组
     * @return {Array} 转化好的字节流数组
     */
    init: function (array) {
      for (var i = 0; i < array.length; i++) {
        array[i] *= 1;
        if (array[i] < 0) {
          array[i] += 256
        }
        if(array[i]>255){
          throw new Error('不合法字节流')
        }
      }
      return array;
    },
    /**
     * 把一段字符串按照utf8编码写到缓冲区中
     * @param {String} str 将要写入缓冲区的字符串
     * @param {Boolean} isGetBytes 是否只得到内容字节(不包括最开始的两位占位字节)
     * @returns {Array} 字节流
     */
    writeUTF: function (str, isGetBytes) {
      var back = [],
        byteSize = 0;
      for (var i = 0; i < str.length; i++) {
        var code = str.charCodeAt(i);
        if (code >= 0 && code <= 127) {
          byteSize += 1;
          back.push(code);
        } else if (code >= 128 && code <= 2047) {
          byteSize += 2;
          back.push((192 | (31 & (code >> 6))));
          back.push((128 | (63 & code)))
        } else if (code >= 2048 && code <= 65535) {
          byteSize += 3;
          back.push((224 | (15 & (code >> 12))));
          back.push((128 | (63 & (code >> 6))));
          back.push((128 | (63 & code)))
        }
      }
      for (i = 0; i < back.length; i++) {
        if (back[i] > 255) {
          back[i] &= 255
        }
      }
      if (isGetBytes) {
        return back
      }
      if (byteSize <= 255) {
        return [0, byteSize].concat(back);
      } else {
        return [byteSize >> 8, byteSize & 255].concat(back);
      }
    },
    /**
     * 把一串字节流按照utf8编码读取出来
     * @param arr 字节流
     * @returns {String} 读取出来的字符串
     */
    readUTF: function (arr) {
      if (Object.prototype.toString.call(arr) == "[object String]") {
        return arr;
      }
      var UTF = "",
        _arr = this.init(arr);
      for (var i = 0; i < _arr.length; i++) {
        var one = _arr[i].toString(2),
          v = one.match(/^1+?(?=0)/);
        if (v && one.length == 8) {
          var bytesLength = v[0].length,
            store = _arr[i].toString(2).slice(7 - bytesLength);
          for (var st = 1; st < bytesLength; st++) {
            store += _arr[st + i].toString(2).slice(2)
          }
          UTF += String.fromCharCode(parseInt(store, 2));
          i += bytesLength - 1
        } else {
          UTF += String.fromCharCode(_arr[i])
        }
      }
      return UTF
    },
    /**
     * 转换成Stream对象
     * @param x
     * @returns {Stream}
     */
    convertStream: function (x) {
      if (x instanceof Stream) {
        return x
      } else {
        return new Stream(x)
      }
    },
    /**
     * 把一段字符串转为mqtt格式
     * @param str
     * @returns {*|Array}
     */
    toMQttString: function (str) {
      return this.writeUTF(str)
    }
  };
  /**
   * 读取指定长度的字节流到指定数组中
   * @param {Stream} m Stream实例
   * @param {number} i 读取的长度
   * @param {Array} a 存入的数组
   * @returns {Array} 存入的数组
   */
  function baseRead(m, i, a) {
    var t = a ? a : [];
    for (var start = 0; start < i; start++) {
      t[start] = m.pool[m.position++]
    }
    return t
  }
  /**
   * 判断浏览器是否支持ArrayBuffer
   */
  var supportArrayBuffer = (function () {
    return !!window.ArrayBuffer;
  })();
  /**
   * 字节流处理实体类
   * @param {String|Array} array 初始化字节流,如果是字符串则按照UTF8的格式写入缓冲区
   * @constructor
   */
  function Stream(array) {
    if (!(this instanceof Stream)) {
      return new Stream(array);
    }
    /**
     * 字节流缓冲区
     * @type {Array}
     */
    this.pool = [];
    if (Object.prototype.toString.call(array) === '[object Array]') {
      this.pool = binaryPot.init(array);
    } else if (Object.prototype.toString.call(array) == "[object ArrayBuffer]") {
      var arr = new Int8Array(array);
      this.pool = binaryPot.init([].slice.call(arr));
    } else if (typeof array === 'string') {
      this.pool = binaryPot.writeUTF(array);
    }
    var self = this;
    //当前流执行的起始位置
    this.position = 0;
    //当前流写入的多少字节
    this.writen = 0;
    //返回当前流执行的起始位置是否已经大于整个流的长度
    this.check = function () {
      return self.position >= self.pool.length
    };
  }
  /**
   * 强制转换为Stream对象
   * @param x
   * @returns {*|Stream}
   */
  Stream.parse = function (x) {
    return binaryPot.convertStream(x);
  };
  Stream.prototype = {
    /**
     * 从缓冲区读取4个字节的长度并转换为int值,position往后移4位
     * @returns {Number} 读取到的数字
     * @description 如果position大于等于缓冲区的长度则返回-1
     */
    readInt: function () {
      if (this.check()) {
        return -1
      }
      var end = "";
      for (var i = 0; i < 4; i++) {
        end += this.pool[this.position++].toString(16)
      }
      return parseInt(end, 16);
    },
    /**
     * 从缓冲区读取1个字节,position往后移1位
     * @returns {Number}
     * @description 如果position大于等于缓冲区的长度则返回-1
     */
    readByte: function () {
      if (this.check()) {
        return -1
      }
      var val = this.pool[this.position++];
      if (val > 255) {
        val &= 255;
      }
      return val;
    },
    /**
     * 从缓冲区读取1个字节,或读取指定长度的字节到传入的数组中,position往后移1或bytesArray.length位
     * @param {Array|undefined} bytesArray
     * @returns {Array|Number}
     */
    read: function (bytesArray) {
      if (this.check()) {
        return -1
      }
      if (bytesArray) {
        return baseRead(this, bytesArray.length | 0, bytesArray)
      } else {
        return this.readByte();
      }
    },
    /**
     * 从缓冲区的position位置按UTF8的格式读取字符串,position往后移指定的长度
     * @returns {String} 读取的字符串
     */
    readUTF: function () {
      var big = (this.readByte() << 8) | this.readByte();
      return binaryPot.readUTF(this.pool.slice(this.position, this.position += big));
    },
    /**
     * 把字节流写入缓冲区,writen往后移指定的位
     * @param {Number|Array} _byte 写入缓冲区的字节(流)
     * @returns {Array} 写入的字节流
     */
    write: function (_byte) {
      var b = _byte;
      if (Object.prototype.toString.call(b).toLowerCase() == "[object array]") {
        [].push.apply(this.pool, b);
        this.writen += b.length;
      } else {
        if (+b == b) {
          if (b > 255) {
            b &= 255;
          }
          this.pool.push(b);
          this.writen++
        }
      }
      return b
    },
    /**
     * 把参数当成char类型写入缓冲区,writen往后移2位
     * @param {Number} v 写入缓冲区的字节
     */
    writeChar: function (v) {
      if (+v != v) {
        throw new Error("writeChar:arguments type is error")
      }
      this.write((v >> 8) & 255);
      this.write(v & 255);
      this.writen += 2
    },
    /**
     * 把字符串按照UTF8的格式写入缓冲区,writen往后移指定的位
     * @param {String} str 字符串
     * @return {Array} 缓冲区
     */
    writeUTF: function (str) {
      var val = binaryPot.writeUTF(str);
      [].push.apply(this.pool, val);
      this.writen += val.length;
    },
    /**
     * 把缓冲区字节流的格式从0至256的区间改为-128至128的区间
     * @returns {Array} 转换后的字节流
     */
    toComplements: function () {
      var _tPool = this.pool;
      for (var i = 0; i < _tPool.length; i++) {
        if (_tPool[i] > 128) {
          _tPool[i] -= 256
        }
      }
      return _tPool
    },
    /**
     * 获取整个缓冲区的字节
     * @param {Boolean} isCom 是否转换字节流区间
     * @returns {Array} 转换后的缓冲区
     */
    getBytesArray: function (isCom) {
      if (isCom) {
        return this.toComplements()
      }
      return this.pool
    },
    /**
     * 把缓冲区的字节流转换为ArrayBuffer
     * @returns {ArrayBuffer}
     * @throw {Error} 不支持ArrayBuffer
     */
    toArrayBuffer: function () {
      if (supportArrayBuffer) {
        return new ArrayBuffer(this.getBytesArray());
      } else {
        throw new Error('not support arraybuffer');
      }
    },
    clear: function () {
      this.pool = [];
      this.writen = this.position = 0;
    }
  };
  return Stream;
});

如何使用?

<script src="binary.js"></script>
<script>
   var ts = TinyStream('我叫张亚涛');
   ts.writeUTF('你好');
   console.log('获取缓冲区字节流:',ts.getBytesArray());
   console.log('当前的缓冲区position为:',ts.position,'writen为:',ts.writen);
   console.log('读取第一个utf8字节流:',ts.readUTF());
   console.log('当前的缓冲区position为:',ts.position,'writen为:',ts.writen);
   console.log('读取第二个utf8字节流:',ts.readUTF());
   console.log('当前的缓冲区position为:',ts.position,'writen为:',ts.writen);
</script>

以后,我可以不用为浏览器段处理二进制而发愁了!!!希望本文分享对大家学习javascript二进制相关知识有所帮助。

Javascript 相关文章推荐
ExtJS 2.2.1的grid控件在ie6中的显示问题
May 04 Javascript
JavaScript中的几个关键概念的理解-原型链的构建
May 12 Javascript
jQuery lazyLoad图片延迟加载插件的优化改造方法分享
Aug 13 Javascript
使用typeof判断function是否存在于上下文
Aug 14 Javascript
Node.js异步I/O学习笔记
Nov 04 Javascript
js实现网页图片延时加载 提升网页打开速度
Jan 26 Javascript
jQuery树插件zTree使用方法详解
May 02 jQuery
详解vue过滤器在v2.0版本用法
Jun 01 Javascript
layer实现关闭弹出层刷新父界面功能详解
Nov 15 Javascript
Angular实现的简单定时器功能示例
Dec 28 Javascript
JavaScript 中的12种循环遍历方法【总结】
May 31 Javascript
在Chrome DevTools中调试JavaScript的实现
Apr 07 Javascript
js实现二级菜单渐隐显示
Nov 03 #Javascript
整理JavaScript创建对象的八种方法
Nov 03 #Javascript
JavaScript实现倒计时代码段Item1(非常实用)
Nov 03 #Javascript
jQuery实用技巧必备(下)
Nov 03 #Javascript
JavaScript实现的多种鼠标拖放效果
Nov 03 #Javascript
JavaScript实现的Tween算法及缓冲特效实例代码
Nov 03 #Javascript
jQuery实现Email邮箱地址自动补全功能代码
Nov 03 #Javascript
You might like
防止用户利用PHP代码DOS造成用光网络带宽
2011/03/01 PHP
php在程序中将网页生成word文档并提供下载的代码
2012/10/09 PHP
YII实现分页的方法
2014/07/09 PHP
PHP使用递归方式列出当前目录下所有文件的方法
2015/06/02 PHP
php验证码实现代码(3种)
2015/09/07 PHP
Prototype RegExp对象 学习
2009/07/19 Javascript
javascript setTimeout和setInterval计时的区别详解
2013/06/21 Javascript
Jquery uploadify图片上传插件无法上传的解决方法
2013/12/16 Javascript
用JS动态改变表单form里的action值属性的两种方法
2016/05/25 Javascript
JS实现table表格数据排序功能(可支持动态数据+分页效果)
2016/05/26 Javascript
js实现为a标签添加事件的方法(使用闭包循环)
2016/08/02 Javascript
ES6下子组件调用父组件的方法(推荐)
2018/02/23 Javascript
Vue 项目中遇到的跨域问题及解决方法(后台php)
2018/03/28 Javascript
jQuery实现鼠标移入移出事件切换功能示例
2018/09/06 jQuery
在js代码拼接dom对象到页面上的模板总结
2018/10/21 Javascript
原生js实现弹幕效果
2020/11/29 Javascript
python实现从网络下载文件并获得文件大小及类型的方法
2015/04/28 Python
Python实现程序的单一实例用法分析
2015/06/03 Python
浅谈python 读excel数值为浮点型的问题
2018/12/25 Python
cProfile Python性能分析工具使用详解
2019/07/22 Python
python 常见的反爬虫策略
2020/09/27 Python
如何利用python读取micaps文件详解
2020/10/18 Python
纯CSS和jQuery实现的在页面顶部显示的进度条效果2例(仿手机浏览器进度条效果)
2014/04/16 HTML / CSS
CSS3 实现的火焰动画
2020/12/07 HTML / CSS
法国体育用品商店:GO Sport
2019/10/23 全球购物
西铁城美国官方网站:Citizen Watch美国
2019/11/08 全球购物
计划生育证明格式及范本
2014/10/09 职场文书
读《教育心理学》心得体会
2016/01/22 职场文书
java设计模式--建造者模式详解
2021/07/21 Java/Android
TypeScript中条件类型精读与实践记录
2021/10/05 Javascript
Java使用JMeter进行高并发测试
2021/11/23 Java/Android
关于Python使用turtle库画任意图的问题
2022/04/01 Python
Python绘制散乱的点构成的图的方法
2022/04/21 Python
Android Studio 计算器开发
2022/05/20 Java/Android
Linux中各个目录的作用与内容
2022/06/28 Servers
基于Redission的分布式锁实战
2022/08/14 Redis