javascript二進位檔案處理方案

來源:互聯網
上載者:User

眾所周知,javascript是不支援二進位檔案和資料的。傳統的做法,是把二進位檔案轉成字元,然後在瀏覽器裡,通過某些技巧把對應字串換成數字,然後做其它處理(傳統方法會在後面講到)。這種處理方式不標準,需要某些“技巧”,甚至通過“欺騙”瀏覽器才能實現。

隨著瀏覽器的進化,出現了新的方案。XMLHttpRequest Level 2增加了對位元據的上傳和下載支援,它可以和File System API, Web Audio API等配合使用。我們的新方案就利用它這個功能。

先睹為快,這裡是個demo.

XHR2方案

XMLHttpRequest Level 2引入responseType和response兩個屬性,它們通知瀏覽器把請求到的資料按照某種格式進行處理。

xhr.responseType
在發送請求之前,根據需求把xhr.responseType設定為’text’、’arraybuffer’、’blob’或者’document’。它的預設值是’text’ 。
xhr.response
獲得了資料之後,根據之前responseType的值,xhr的response屬性就是DOMString、ArrayBuffer、Blob或者Document格式的資料

利用上面兩個屬性,我們可以把位元據格式化為ArrayBuffer,而不是字串。然後使用BlobBuilder api把資料轉化為blob處理:

?
1234567891011121314151617 BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder; var xhr = new XMLHttpRequest();xhr.open('GET', '/path/to/image.png', true);xhr.responseType = 'arraybuffer'; xhr.onload = function(e) {  if (this.status == 200) {    var bb = new BlobBuilder();    bb.append(this.response); // Note: not xhr.responseText     var blob = bb.getBlob('image/png');    ...  }}; xhr.send();

這樣處理就方便多了。通過使用ArrayBufferView,我們可以更方便的處理資料。它對arraybuffer進行資料封裝,使我們可以像處理數組一樣處理請求到的位元據。view有好幾種格式,Float32Array、Float64Array、Int16Array、Int32Array、Int8Array、Uint16Array、Uint32Array、Uint8Array。個人覺得,處理位元據Uint8Array應該是最方便的了。下面是代碼例子:

?
12345678910111213 var xhr = new XMLHttpRequest();xhr.open('GET', '/path/to/image.png', true);xhr.responseType = 'arraybuffer'; xhr.onload = function(e) {  var uInt8Array = new Uint8Array(this.response); // this.response == uInt8Array.buffer  var byte3 = uInt8Array[4]; // byte at offset 4  if(byte3 == 0xA9){      alert('the first data is 0xA9');  }}; xhr.send();

它對瀏覽器的要求是firefox6+、chrome9+,那其它低版本的瀏覽器怎麼辦呢?降級使用傳統方案唄

傳統處理方案

傳統方案的思路:請求資料時把mime type重寫成自訂的格式的charset。然後處理請求資料中的每一個byte,與0xff進行與,獲得8位的資料。例子如下:

?
123456789101112131415161718 var xhr = new XMLHttpRequest();xhr.open('GET', '/path/to/image.png', true); // Hack to pass bytes through unprocessed.xhr.overrideMimeType('text/plain; charset=x-user-defined'); xhr.onreadystatechange = function(e) {  if (this.readyState == 4 && this.status == 200) {    var binStr = this.responseText;    for (var i = 0, len = binStr.length; i < len; ++i) {      var c = binStr.charCodeAt(i);      //String.fromCharCode(c & 0xff);      var byte = c & 0xff;  // byte at offset i    }  }}; xhr.send();

通過設定mimetype技巧,我們擷取了代表位元據的字串,然後處理字串,得到我們想到的資料。此方法不被推薦,因為這種方法每次都要把字元強制轉換成我們需要的格式,而且需要通過小技巧“騙”一下瀏覽器。

ie方案

ie9-不支援overrideMimeType方法,怎麼辦呢?前幾天ququ的文章《圖片自動旋轉的前端實現方案》中提到使用vb做資料處理,實驗了一下,還真行。vb裡有很多位元組處理的函數,這裡只介紹用到的三個:

MidB
返回字串( String)的一部分。用法result = MidB( 源字串, 起點, [長度] ),MidB 將源字串當作一組位元組,而不是一組字元來處理。MidB 應被用在源字串代表位元據的情況下。
AscB
AscB 返回首位元組。它與MidB一起使用,可以獲得資料中指定位置的位元組。
LenB
獲得字串中的位元組總數。LenB 函數將字串當作一組位元組而不是一組字元。當字串代表位元據時應當使用此函數。

通這個三個函數,我們可以擷取ajax請求到的字串對應的位元組資料了。下面是一段摘抄的代碼例子:

?
123456789101112131415161718 document.write(    &quot;<script type='text/vbscript'>\r\n"    + "Function IEBinary_getByteAt(strBinary, iOffset)\r\n"    + " IEBinary_getByteAt = AscB(MidB(strBinary, iOffset + 1, 1))\r\n"    + "End Function\r\n"    + "Function IEBinary_getBytesAt(strBinary, iOffset, iLength)\r\n"    + "  Dim aBytes()\r\n"    + "  ReDim aBytes(iLength - 1)\r\n"    + "  For i = 0 To iLength - 1\r\n"    + "   aBytes(i) = IEBinary_getByteAt(strBinary, iOffset + i)\r\n"    + "  Next\r\n"    + "  IEBinary_getBytesAt = aBytes\r\n"    + "End Function\r\n"    + "Function IEBinary_getLength(strBinary)\r\n"    + " IEBinary_getLength = LenB(strBinary)\r\n"    + "End Function\r\n"    + "</script>\r\n&quot;);

這段代碼都過document.write的方式,在頁面中插入了兩個三個vb函數,IEBinary_getByteAt返回指定位置的位元組,IEBinary_getBytesAt返回從指定位置開始的指定長度的位元組數組,IEBinary_getLength返回字串中位元組個數。我們把ajax的responseBody中的字串通過這三個函數處理,就可以獲得對應的位元據。

注意:在ie低版本中,js處理能力不強,所以如果要處理的資料太大的話,很容易使導致cpu 100%,甚至瀏覽器崩潰。

代碼例子:

?
1234567891011121314 var xhr = new ActiveXObject("Microsoft.XMLHTTP");xhr.onreadystatechange = function() {    if (xhr.readyState == 4) {        if (xhr.status == "200" || xhr.status == "206" || xhr.status == "0") {            var blen = IEBinary_getLength(xhr.responseBody),                byteArray =  new VBArray(IEBinary_getBytesAt(xhr.responseBody, 0, blen)).toArray();             rpg.drawNpc(byteArray);        }        xhr = null;    }};xhr.open('GET', url, true);xhr.send(null);

參考文章:

New Tricks in XMLHttpRequest2

JavaScript typed arrays

圖片自動旋轉的前端實現方案

Read EXIF data with Javascript

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.