js 字節數組轉數字以及數字轉字節數組


javascript通過ArrayBuffer和DataView實現字節數組和數字之間的相互轉換

注意!我這里的所有函數用的都是大端字節序(高位在前,低位在后),即數據的高字節,保存在內存的低地址中,而數據的低字節,保存在內存的高地址中

舉例:2個字節的無符號整型1的二進制表示

大端模式: 0000 0000 0000 0001

小端模式: 0000 0001 0000 0000

如果字節序不一致,解析的數據就會出錯!如果你的數據是小端模式,就需要翻轉數組,或者重寫這些函數,DataView的setInt32和getInt32之類的函數可以傳入一個參數來控制大端還是小端,我采用的是默認的情況下的大端模式

具體代碼如下

    test();
    function test() {
        var bytes = getFloat64Bytes(-3.33);
        alert(bytes);
        alert(toFloat64(bytes));
    }
    //構建一個視圖,把字節數組寫到緩存中,索引從0開始,大端字節序
    function getView(bytes) {
        var view = new DataView(new ArrayBuffer(bytes.length));
        for (var i = 0; i < bytes.length; i++) {
            view.setUint8(i, bytes[i]);
        }
        return view;
    }
    //將字節數組轉成有符號的8位整型,大端字節序
    function toInt8(bytes) {
        return getView(bytes).getInt8();
    }
    //將字節數組轉成無符號的8位整型,大端字節序
    function toUint8(bytes) {
        return getView(bytes).getUint8();
    }
    //將字節數組轉成有符號的16位整型,大端字節序
    function toInt16(bytes) {
        return getView(bytes).getInt16();
    }
    //將字節數組轉成無符號的16位整型,大端字節序
    function toUint16(bytes) {
        return getView(bytes).getUint16();
    }
    //將字節數組轉成有符號的32位整型,大端字節序
    function toInt32(bytes) {
        return getView(bytes).getInt32();
    }
    //將字節數組轉成無符號的32位整型,大端字節序
    function toUint32(bytes) {
        return getView(bytes).getUint32();
    }
    //將字節數組轉成32位浮點型,大端字節序
    function toFloat32(bytes) {
        return getView(bytes).getFloat32();
    }
    //將字節數組轉成64位浮點型,大端字節序
    function toFloat64(bytes) {
        return getView(bytes).getFloat64();
    }

    //將數值寫入到視圖中,獲得其字節數組,大端字節序
    function getUint8Array(len, setNum) {
        var buffer = new ArrayBuffer(len);  //指定字節長度
        setNum(new DataView(buffer));  //根據不同的類型調用不同的函數來寫入數值
        return new Uint8Array(buffer); //創建一個字節數組,從緩存中拿取數據
    }
    //得到一個8位有符號整型的字節數組,大端字節序
    function getInt8Bytes(num) {
        return getUint8Array(1, function (view) { view.setInt8(0, num); })
    }
    //得到一個8位無符號整型的字節數組,大端字節序
    function getUint8Bytes(num) {
        return getUint8Array(1, function (view) { view.setUint8(0, num); })
    }
    //得到一個16位有符號整型的字節數組,大端字節序
    function getInt16Bytes(num) {
        return getUint8Array(2, function (view) { view.setInt16(0, num); })
    }
    //得到一個16位無符號整型的字節數組,大端字節序
    function getUint16Bytes(num) {
        return getUint8Array(2, function (view) { view.setUint16(0, num); })
    }
    //得到一個32位有符號整型的字節數組,大端字節序
    function getInt32Bytes(num) {
        return getUint8Array(4, function (view) { view.setInt32(0, num); })
    }
    //得到一個32位無符號整型的字節數組,大端字節序
    function getUint32Bytes(num) {
        return getUint8Array(4, function (view) { view.setUint32(0, num); })
    }
    //得到一個32位浮點型的字節數組,大端字節序
    function getFloat32Bytes(num) {
        return getUint8Array(4, function (view) { view.setFloat32(0, num); })
    }
    //得到一個64位浮點型的字節數組,大端字節序
    function getFloat64Bytes(num) {
        return getUint8Array(8, function (view) { view.setFloat64(0, num); })
    }

    ////下面幾個為另一種實現方式的版本,只實現了簡單幾種,其他的實現起來比較麻煩,所以就中途放棄了
    //function toInt32(bytes) {
    //    return ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) | ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);
    //}
    //function toUInt16(bytes) {
    //    return ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);
    //}
    //function toInt16(bytes) {
    //    return bytes[0] >> 7 == 0 ? toUInt16(bytes) : toUInt16(bytes) - 65536;
    //}
    //function getInt32Bytes(num) {
    //    return [num >> 24 & 0xFF, num >> 16 & 0xFF, num >> 8 & 0xFF, num & 0xFF];
    //}
    //function getUint16Bytes(num) {
    //    return [num >> 8 & 0xFF, num & 0xFF];
    //}
    //function getInt16Bytes(num) {
    //    return num >= 0 ? getUint16Bytes(num) : getUint16Bytes(65536 + num);
    //} 

還有個小問題,我這邊數字轉字節數組函數的返回值都是Uint8Array,這是一個TypeArray類型,它和Array不是一個東西,定長的,不能push,而且Array.concat無法正常連接Uint8Array數組(會將Uint8Array整體作為一個對象),如果使用的是Array,就需要自己處理下,或者直接在getUint8Array函數中將Uint8Array轉成Array

    //將數值寫入到視圖中,獲得其字節數組,大端字節序
    function getUint8Array(len, setNum) {
        var buffer = new ArrayBuffer(len); //指定字節長度
        setNum(new DataView(buffer)); //根據不同的類型調用不同的函數來寫入數值
        var uint8Array = new Uint8Array(buffer); //創建一個字節數組,從緩存中拿取數據
        var arr = new Array();  //將Uint8Array轉成Array數組,不考慮性能問題
        for (var i = 0; i < uint8Array.byteLength; i++) {  //尷尬,Uint8Array沒有length,只有byteLength,之前寫的竟然沒測就發布了,現在才發現問題
            arr.push(uint8Array[i]);
        }
        return arr;
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM