前端進階:二進制數據的操控----附項目代碼

前端進階,起飛遠航

引言: 近期,工做中發現,有些前端小夥伴不多接觸到二進制數據,因此將項目中二進制數據的應用和你們分享一下,適合入門瞭解,高手慎入,歡迎拍磚。前端

項目背景: 基於公司原有圖形處理的二進制數據文件(公司自定義的二進制數據格式),實現Canvas繪圖。ajax

話說:項目開始的時候我也是一臉懵逼,這麼多技術難點須要攻克,1. 如何請求二進制數據流?2. 如何解壓二進制數據?3. 如何讀取二進制數據?……canvas


接下來咱們一一攻破:見招拆招後端

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 對象中讀寫多種數值類型的底層接口,在讀寫時不用考慮平臺字節序問題。bash

接下來咱們能夠建立一個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

  1. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
  2. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/DataView
  3. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
相關文章
相關標籤/搜索