天天看点

js操作二进制数据的对象接口一.浏览器环境二.node环境

本文主要从前端(浏览器)和后端(node)环境出发,分别讲述如何用js去调用环境提供的接口,而操控二进制数据

一.浏览器环境

前端环境下,js主要可以调用ArrayBuffer和Blob这两个对象接口

ArrayBuffer

ArrayBuffer 对象是ES6新加入的标准,表示一段二进制数据,用来模拟内存里面的数据。这个对象可以看作内存数据的表达

浏览器原生提供ArrayBuffer()构造函数,用来生成实例。它接受一个整数作为参数,表示这段二进制数据占用多少个字节

var buffer = new ArrayBuffer(8);  //实例对象buffer占用8个字节
buffer.byteLength     // 8,属性byteLength,表示当前实例占用的内存长度(单位字节)
           

ArrayBuffer 对象有实例方法slice(),用来复制一部分内存。它接受两个整数参数,分别表示复制的开始位置(从0开始)和结束位置(复制时不包括结束位置),如果省略第二个参数,则表示一直复制到结束

var buf1 = new ArrayBuffer(12); // 生成一个可以12个字节的连续内存,每个字节的默认值是0
var buf2 = buf1.slice(0);   //实例buf2复制了buf1
           

注意:ArrayBuffer不能直接读写,只能通过视图进行操作,所以虽然可以调用,但是前端主要还是使用Blob

Blob

Blob(Binary Large Object 二进制大型对象),它与 ArrayBuffer 的区别在于,Blob 对象表示一个二进制文件的数据内容,比如一个图片文件的内容就可以通过 Blob 对象读写,它用于操作二进制文件,而 ArrayBuffer 用于操作内存

Blob构造函数接受两个参数。第一个参数是数组,成员是字符串或二进制对象,表示新生成的Blob实例对象的内容;第二个参数是可选的,是一个配置对象,目前只有一个属性type,它的值是一个字符串,表示数据的 MIME 类型,默认是空字符串

//用Blob保存json数据
var obj = { name: 'qgq' };
var blob = new Blob([ JSON.stringify(obj) ], {type : 'application/json'});
           

Blob具有两个实例属性size和type,分别返回数据的大小和类型,实例方法slice,用来拷贝原来的数据,返回的也是一个Blob实例

Blob的应用

1.浏览器点击下载功能

<a download="data.txt" id="getData">下载</a>   

var data= 'Hello world!';  
var blob = new Blob([data], {   
  type: 'text/html,charset=UTF-8'   
});
window.URL = window.URL || window.webkitURL; 
document.querySelector("#getData").href = URL.createObjectURL(blob);
           

上面的代码将Blob URL赋值给a标签,点击后,会提示下载文本文件为data.txt,文件内容为“Hello World”

2.分割大文件上传(利用Blob中slice方法)

function upload(blobOrFile){
  var xhr = new XMLHttpRequest();
  xhr.open('POST','/server/upload',true);
  xhr.onload = function(e) { ... };
  xhr.send(blobOrFile);
}

document.querySelector('input[type="file"]').addEventListener('change' , function(e){
    var blob = this.files[0];
    const BYTES_PER_CHUNK = 1024 * 1024; //1MB chunk size
    const SIZE = blob.size;
    
     var start = 0;
     var end = BYTES_PER_CHUNK;
     while(start < SIZE){
        upload(blob.slice(start, end));
        start = end;
        end = start + BYTES_PER_CHUNK;
     }
 },false);
           

3.解决canvas图片跨域

如果想要获取一张图片上某个像素点的色值,可以使用canvas的getImageData来拿到数据,但是在canvas中,跨域图片是不能获取其图像信息的,如果取跨域的图片像素信息,就会出现跨域错误

//下面代码会报错The canvas has been tainted by cross-origin data.
const url = 'https://developer.mozilla.org/static/img/web-docs-sprite.22a6a085cf14.svg'
const img = new Image()
img.onload = function () {
  ctx.drawImage(img, 0, 0)
  addEventListener('click', pick)
}

img.src = url
function pick (e) {
  const data = ctx.getImageData(e.layerX, e.layerY, 1, 1).data
  console.log(data)
}
           

解决这个问题,首先服务端运行该资源跨域访问,另外,在img上添加一个crossOrigin

另可以通过Blob来解决

const url = 'https://developer.mozilla.org/static/img/web-docs-sprite.22a6a085cf14.svg'

const xhr = new XMLHttpRequest()
xhr.open('GET', url, true)
xhr.responseType = 'blob'

xhr.onload = function () {
  if (this.status === 200) {
    const blob = this.response

    const img = new Image()
    const imgObject = URL.createObjectURL(blob)
    img.onload = function () {
      ctx.drawImage(img, 0, 0)
      canvas.addEventListener('click', pick)
      document.body.removeChild(img)
      URL.revokeObjectURL(imgObject)
    }
    img.src = imgObject
    document.body.appendChild(img)
  }
}

xhr.send()

function pick (e) {
  const data = ctx.getImageData(e.layerX, e.layerY, 1, 1).data
  console.log(data)
}
           

4.隐藏视频原路径,blob:http://

<video controls id='sound'/>

<script>
  var xhr = new XMLHttpRequest();
  xhr.open('POST','./server/video',true);
  xhr.responseType = 'blob';
  xhr.onload = function(e){
    if(this.status == 200){
       var blob = this.response;
        document.getElementById("sound").src =  URL.createObjectURL(blob);
     }
  }
  xhr.send();
</script>
           

二.node环境

二进制数组,用来处理二进制数据的类

二进制数组由三类对象组成:

1.ArrayBuffer对象:前面也介绍了,代表内存中原始的二进制数据,本身不能直接读写,需要通过视图来操作

2.TypedArray视图:共包括 9 种类型的视图,比如Uint8Array(无符号 8 位整数)数组视图, Int16Array(16 位整数)数组视图, Float32Array(32 位浮点数)数组视图等等

3.DataView视图:可以自定义复合格式的视图,比如第一个字节是 Uint8(无符号 8 位整数)、第二、三个字节是 Int16(16 位整数)、第四个字节开始是 Float32(32 位浮点数)等等,此外还可以自定义字节序

Node中的Buffer类是以更优化和更适合Nodejs的方式实现了Uint8Array API,意思就是Buffer类其实是TypedArray(Uint8Array)的nodejs实现

ArrayBuffer有一个静态方法isView,判断参数是否为视图实例

const buffer = new ArrayBuffer(12);
buffer.byteLength; // 12
buffer.slice(0, 3); // 用法和数组一致,拷贝buffer的前三个字节生成一个新的ArrayBuffer对象
ArrayBuffer.isView(buffer); // false
const dataView = new DataView(buffer);
ArrayBuffer.isView(dataView); // true
           

继续阅读