资讯专栏INFORMATION COLUMN

前端进阶:二进制数据的操控----附项目代码

alogy / 2886人阅读

摘要:引言近期,工作中发现,有些前端小伙伴很少接触到二进制数据,所以将项目中二进制数据的应用和大家分享一下,适合入门了解,高手慎入,欢迎拍砖。这样,我们就完成了二进制数据的请求解压读取和存储了。

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

项目背景: 基于公司原有图形处理的二进制数据文件(公司自定义的二进制数据格式),实现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

https://developer.mozilla.org...

https://developer.mozilla.org...

https://developer.mozilla.org...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94525.html

相关文章

  • 非计算机专业小白自学爬虫全指南(资源)

    摘要:爬虫是我接触计算机编程的入门。练练练本文推荐的资源就是以项目练习带动爬虫学习,囊括了大部分爬虫工程师要求的知识点。拓展阅读一文了解爬虫与反爬虫最后,请注意,爬虫的工作机会相对较少。 爬虫是我接触计算机编程的入门。哥当年写第一行代码的时候别提有多痛苦。 本文旨在用一篇文章说透爬虫如何自学可以达到找工作的要求。 爬虫的学习就是跟着实际项目去学,每个项目会涉及到不同的知识点,项目做多了,自然...

    CarlBenjamin 评论0 收藏0
  • 【备战春招/秋招系列】美团面经总结基础篇 (详解答案)

    摘要:不同于个人面经,这份面经具有普适性。我在前面的文章中也提到了应该怎么做自我介绍与项目介绍,详情可以查看这篇文章备战春招秋招系列初出茅庐的程序员该如何准备面试。是建立连接时使用的握手信号。它表示确认发来的数据已经接受无误。 showImg(https://segmentfault.com/img/remote/1460000016972448?w=921&h=532); 该文已加入开源文...

    Leck1e 评论0 收藏0
  • Java学习路线总结,搬砖工逆袭Java架构师(全网最强)

    摘要:哪吒社区技能树打卡打卡贴函数式接口简介领域优质创作者哪吒公众号作者架构师奋斗者扫描主页左侧二维码,加入群聊,一起学习一起进步欢迎点赞收藏留言前情提要无意间听到领导们的谈话,现在公司的现状是码农太多,但能独立带队的人太少,简而言之,不缺干 ? 哪吒社区Java技能树打卡 【打卡贴 day2...

    Scorpion 评论0 收藏0

发表评论

0条评论

alogy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<