博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端进阶:二进制数据的操控----附项目代码
阅读量:6256 次
发布时间:2019-06-22

本文共 4160 字,大约阅读时间需要 13 分钟。

前端进阶,起飞远航

引言: 近期,工作中发现,有些前端小伙伴很少接触到二进制数据,所以将项目中二进制数据的应用和大家分享一下,适合入门了解,高手慎入,欢迎拍砖。

项目背景: 基于公司原有图形处理的二进制数据文件(公司自定义的二进制数据格式),实现Canvas绘图。

话说:项目开始的时候我也是一脸懵逼,这么多技术难点需要攻克,1. 如何请求二进制数据流?2. 如何解压二进制数据?3. 如何读取二进制数据?……


接下来我们一一攻破:见招拆招

1. 数据请求arraybuffer

基于ajax请求,设置接受的数据格式为arraybuffer类型,基于流文件的读取是需要异步来处理的,否则数据可能有丢失。

let oReq = null;  if (window.XMLHttpRequest) {    oReq = new XMLHttpRequest();  }  else {    oReq = new ActiveXObject('Microsoft.XMLHTTP');  }  oReq.onprogress = this.updateProgress;//下载进度;  oReq.responseType = "arraybuffer";  oReq.onload = function () {  // 数据下载完成会触发;    if ((oReq.status >= 200 && oReq.status < 300) || oReq.status == 304) {      var arrayBuffer = oReq.response;      // 接下来的任务      ReadFromByteArray(arrayBuffer); //读取收到的数据    }    if (oReq.status === 404) {      alert("找不到对应文件!")    }  };  oReq.open("GET", reqUrl, true);  oReq.send(null);

2. 数据读取ArrayBufferDataView

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。
ArrayBuffer 不能直接操作,而是要通过类型数组对象或 DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

2.1 校验数据的大小

function ReadFromByteArray(buffer){  parseInt(buffer.byteLength / 1024);//文件大小,单位KB;    if (buffer.byteLength < 64) {     // 失败     console.log("文件格式不对:长度小于64");     return false;     } else {     // 成功 解压数据   }}
DataView 视图是一个可以从
ArrayBuffer 对象中读写多种数值类型的底层接口,在读写时不用考虑平台字节序问题。

接下来我们可以创建一个DataView 对象实例,此方法适合顺序存储的数据读取,非顺序(如增量式存储的数据不能按顺序读取,需要安装table中索引读取,否则会读错)。js提供了基本的二进制读取API,为了不用手动计算偏移量,我们可以对基础API进行封装,

DataView常用读取数据的API
getFloat32()getFloat64()getInt16()getInt32()getInt8()getUint16()getUint32()getUint8()

2.2 校验文件名称

let dataView = new DataView(buffer, 0); //将上面获取的buffer传入到视图中let headstr = headerFiler.ReadUTFBytes(5);//读取5个UTF8字节,结果为文件格式if (headstr != "DWG") { //DWG为文件的格式,存放在数据结构的头部 return false;}else{// 继续读取数据}

3. 数据解压TypedArraypako.js

一个
TypedArray 对象描述一个底层的二进制数据缓存区的一个类似数组(array-like)视图。事实上,没有名为
TypedArray的全局对象,也没有一个名为的
TypedArray构造函数。相反,有许多不同的全局对象,下面会列出这些针对特定元素类型的类型化数组的构造函数。在下面的页面中,你会找到一些不管什么类型都公用的属性和方法。

为了减少数据的传入,后端会对二进制数据进行压缩,前端难道要手写解压代码?就算你敢写,你是否敢用?当然寻找三方插件,关于js二进制数据的解压插件还真不多,我选用了pako.js,移动端暂为发现严重兼容性问题,PC端(IE)存在,一定慎用。期待推荐更加三方。

3.1 创建TypedArray

先将buffer转换为类型数组TypedArray,以便读取和操控。

let compressdata = new Uint8Array(buffer, byteOffset, length);//把上面获取`buffer`转换成可操控的`TypedArray`。创建一个无符号整型的TypedArray,偏移量为byteOffset,长度为length。
Tips:偏移量为
byteOffset类似于数组的索引,默认为0, 设置后,从此开始读取。如:
const compressdata = new Uint8Array(buffer, 4, 10);//从第4个字节开始读取,长度为10个字节

3.2 解压数据

利用pako.js解压数据

let uncompress = pako.inflate(compressdata);//解压数据;let uncompressdata = uncompress.buffer;// ArrayBuffer {}let dataViewData = new DataView(uncompressdata, 0);//解压后数据;
Tips:js中的number数据类型,无论数字的大小,都将占用8个字节,即64位,就是Java 中double类型的长度;1字符串会占用2字节,即16位。
js中此种规定,省去了我们声明变量时对数据大小的计算,方便使用,但是,这样就会造成浪费大量的存储空间,明显增大数据的大小。及其不便于大数据的传输,所以会对数据进行压缩。

封装数据读取的API,避免手动计算偏移量

function WsFiler(dataView) {    this.dataView = dataView;    this.dataView.position = 0;}WsFiler.SEEK_BEGIN = 0;WsFiler.SEEK_SET = 0;WsFiler.SEEK_CUR = 1;WsFiler.SEEK_END = 2;WsFiler.prototype.ReadByte = function () {    var b = this.dataView.getUint8(this.dataView.position);    this.dataView.position++;    return b;}WsFiler.prototype.ReadShort = function () {    var s = this.dataView.getInt16(this.dataView.position, true);    this.dataView.position += 2;    return s;};WsFiler.prototype.ReadInt32 = function () {    var int32 = this.dataView.getInt32(this.dataView.position, true);    this.dataView.position += 4;    return int32;};WsFiler.prototype.ReadUInt32 = function () {    var uint32 = this.dataView.getUint32(this.dataView.position, true);    this.dataView.position += 4;    return uint32;}WsFiler.prototype.ReadUtf8String = function () {    var len = this.ReadInt32();//字符串长度;    return this.ReadUTFBytes(len);};WsFiler.prototype.ReadFloat = function () {    var ret = this.dataView.getFloat32(this.dataView.position, true);    this.dataView.position += 4;    return ret;};WsFiler.prototype.ReadDouble = function () {    var ret = this.dataView.getFloat64(this.dataView.position, true);    this.dataView.position += 8;    return ret;}

4. 数据存储:

读取到的数据可以任意操控,可以创建一个数组进行存储。便于我们的后续操控。数据的存储就相对简单了,根据需要将数据拆分即可。


这样,我们就完成了二进制数据的请求、解压、读取和存储了。

后续继续分享,用canvas把我们读到的数据画到网页上。

欢迎大家拍砖。不胜感谢!

参考文献:MDN

转载地址:http://uqnsa.baihongyu.com/

你可能感兴趣的文章
ASP.NET之Javascript脚本的应用
查看>>
vlan间的互通
查看>>
ldconfig详解
查看>>
VBScript 页面的简单样例
查看>>
用c语言指针实现给整形数组冒泡排序
查看>>
ORA-01075,ORA-09925 Read-only file system问题一例
查看>>
Script:收集介质恢复诊断信息
查看>>
SocketIO 随笔
查看>>
Maven学习三之新建maven项目
查看>>
HTML5本地存储-localStorage如何实现定时存储
查看>>
LAMP之Centos6.5安装配置Apache(二)
查看>>
Tomcat集群
查看>>
shell脚本中输出带颜色字体实例分享及chrony时间同步
查看>>
简单计时
查看>>
面试心得
查看>>
linux系统时间同步,硬件时钟和系统时间同步,时区的设置
查看>>
CentOS下载包格式说明
查看>>
VMware Vsphere 6.0安装配置 二安装vcenter server程序
查看>>
关于CISCO asa5510防火墙端口映射配置
查看>>
2012年6月美国最佳虚拟主机提供商TOP12性能评测
查看>>