javascript的二进制操作

2018-02-09 fishedee 前端

1 概述

javascript中的二进制操作,主要讨论的是浏览器中的blob,ArrayBuffer,DataView,TypeArray的操作。

2 ArrayBuffer

var a = new ArrayBuffer(8)
console.log(a,a.byteLength);
var b = a.slice(0,4);
console.log(b,b.byteLength);

ArrayBuffer的操作只有以上三种,建立一个固定长度的arrayBuffer,获取arraybuffer的长度以及将一个arraybuffer取出一部分。要注意的是,为什么要arraybuffer要这么设计。因为,直接用js的array操作二进制时,array需要支持动态扩容和缩容,所以内部实现是相当低效的。arraybuffer相当于一个固定长度的array,它不需要考虑动态扩容和缩容,内部实现效率更高。

3 TypeArray

Int8Array
Uint8Array
Uint8ClampedArray
Int16Array
Uint16Array
Int32Array
Uint32Array
Float32Array
Float64Array

TypeArray是以上的array的总称,它的意思将二进制的arrayBuffer看成是单一类型的数组,然后在这个类型化的数组上进行存取操作。

var a = new ArrayBuffer(8);
console.log(a,a.byteLength);

var uint8array=new Uint8Array(a);
uint8array[0]=01;
uint8array[1]=02;
uint8array[2]=03;
uint8array[3]=04;
console.log(uint8array,uint8array[2],uint8array.length);
    
var uint8array2 = uint8array.subarray(1,3);
uint8array2[0] = 07;
uint8array2[1] = 08;

console.log(uint8array,uint8array.length);
console.log(uint8array2,uint8array2.length);
console.log(uint8array.buffer,uint8array2.buffer);

var uint8array3 = uint8array.slice(1,3);
uint8array3[0] = 09;
uint8array3[1] = 10;
console.log(uint8array,uint8array.length);
console.log(uint8array3,uint8array3.length);
console.log(uint8array.buffer,uint8array3.buffer);

以uint8array为例子,将arraybuffer存进去,那么uint8array就能作为arraybuffer的视图进行存取操作。要注意的是,subarray与slice的区别。subarray是引用原来的arraybuffer的新视图,slice是复制原来的arraybuffer的新视图,它们是不一样的。

4 DataView

var a = new ArrayBuffer(8);
console.log(a,a.byteLength);

var uint8array=new Uint8Array(a);
console.log(uint8array);
    
var dataview = new DataView(a);
dataview.setUint8(0,11);
dataview.setUint16(1,12);
dataview.setUint32(3,13);
console.log(dataview,dataview.byteLength);
console.log(uint8array);

var output = "";
for( var i = 0 ; i != dataview.byteLength;i++ ){
    var single = dataview.getUint8(i);
    output += single+",";
}
console.log(output);

TypeArray是将arraybuffer看成是单一类型的二进制数据,那么DataView是将arraybuffer看成是混合类型的二进制数据。它可以通过getXXX和setXXX对arraybuffer进行存取的操作。要注意的是,对于多字节类型,它同时支持大端和小端的存取操作,默认为大端操作。

5 Blob

blob与arraybuffer相当相似,唯一不同的是,它是不可修改的,它不像arraybuffer能提供视图来修改内部数据,blob一旦创建以后就是不可修改的,一般用来存放图片,文件的数据。

function output(blob){
    var reader = new FileReader();
    reader.onload = function (e) {
        var buf = new Uint8Array(reader.result);
         console.info(buf);
    }
    reader.readAsArrayBuffer(blob);
}
var blob = new Blob(["abcdefg"], {type : 'text/html'});
output(blob);

var buffer2 = new ArrayBuffer(8);
var blob2 = new Blob([buffer2]);
output(blob2);

var uint8array = new Uint8Array(buffer2);
console.log(uint8array);
uint8array[0] = 7;
console.log(uint8array);
output(blob2);

使用arraybuffer创建blob2以后,即使arraybuffer修改了,blob2也是原来的数据,这表明blob2是immutable的。另外,注意一下blob的读取方式,是通过reader进行的。

6 Buffer

function newBuffer(){
    var buffer = Buffer.from("Hello World");
    for( var i = 0 ; i != buffer.byteLength ;i ++ ){
        console.log(buffer[i]);
    }
    buffer[0] = "M".charCodeAt(0);
    var buffer2 = Buffer.from("CCDXXX");
    var buffer3 = Buffer.concat([buffer,buffer2]);
    return buffer3.slice(0,15);
}

function toString(buffer){
    return buffer.toString('utf-8');
}

function toArrayBuffer(buffer){
    return buffer.buffer.slice(buffer.byteOffset,buffer.byteOffset+buffer.byteLength);
}

function toUint8Array(buffer){
    return new Uint8Array(buffer.buffer,buffer.byteOffset,buffer.byteLength);
}

var buffer = newBuffer();
console.log(toString(buffer));
console.log(toArrayBuffer(buffer));
console.log(toUint8Array(buffer));

buffer是node环境下操作二进制的类型,它类比于ArrayBuffer,但是比ArrayBuffer的功能更强大,除了有ArrayBuffer的创建,获取长度,截取,和读写某个位置的数据外,它提供了concat,copy,compare,toString的工具函数,方便了我们操作二进制的数据。同样地,它也能转换到ArrayBuffer,TypeArray,DataaView和Blob上。

7 总结

挺简单的,但也是容易忽略的小知识。

相关文章