添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Blob 对象表示一个不可变、原始数据的类文件对象。Blob 表示的不一定是JavaScript原生格式的数据。 File 接口基于 Blob ,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。

ArrayBuffer

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。

它是一个字节数组,通常在其他语言中称为“byte array”。

你不能直接操作 **ArrayBuffer** 的内容,而是要通过 类型数组对象 **DataView** 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容

总结:要操作二进制,首先需要把二进制数据放在一个地方,ArrayBuffer就是充当这样一个容器的作用。

区别:Blob与ArrayBuffer的区别在于,Blob是不可变的数据,而ArrayBuffer是可以编辑的。

类型化数组(TypedArray 对象)

单个元素值的范围

大小(bytes)

Web IDL 类型

C 语言中的等价类型

Int8Array

-128 to 127

8 位二进制有符号整数

int8_t

Uint8Array

0 to 255

8 位无符号整数(超出范围后从另一边界循环)

octet

uint8_t

Uint8ClampedArray

0 to 255

8 位无符号整数(超出范围后为边界值)

octet

uint8_t

Int16Array

-32768 to 32767

16 位二进制有符号整数

short

int16_t

Uint16Array

0 to 65535

16 位无符号整数

unsigned short

uint16_t

Int32Array

-2147483648 to 2147483647

32 位二进制有符号整数

int32_t

Uint32Array

0 to 4294967295

32 位无符号整数

unsigned long

uint32_t

Float32Array

1.2 × 10-38 to 3.4 × 1038

32 位 IEEE 浮点数(7 位有效数字,如 1.1234567

unrestricted float

float

Float64Array

5.0 × 10-324 to 1.8 × 10308

64 位 IEEE 浮点数(16 有效数字,如 1.123...15 )

unrestricted double

double

BigInt64Array

-263 to 263-1

64 位二进制有符号整数

bigint

int64_t (signed long long)

BigUint64Array

0 to 264-1

64 位无符号整数

Int8Array是8 位二进制有符号整数,Uint8Array是8 位无符号整数,其中有符号的意思是数组中的元素可以存在符号,即可以是负数。

var ui= new Uint8Array([1, -2, 3]);
console.log(ui);//Uint8Array(3) [1, 254, 3]
var Int= new Int8Array([1, -2, 3]);
console.log(Int);//Int8Array(3) [1, -2, 3]

Uint8Array表示数组中每个元素占8位(1个字节),Uint16Array表示数组中每个元素占16位(2个字节)

var ui8= new Uint8Array([1, -2, 3, 4]);
var ui16= new Uint16Array([1, 3]);
console.log(ui8.byteLength);//4
console.log(ui16.byteLength);//4

每一种视图都有一个BYTES_PER_ELEMENT常数,表示这种数据类型占据的字节数。刚好验证了上面。

Uint8Array.BYTES_PER_ELEMENT//1
Uint16Array.BYTES_PER_ELEMENT//2

为什么会有Blob

一直以来,JS都没有比较好的可以直接处理二进制的方法。而blob的存在,允许我们可以通过js直接操作二进制数据。

生成Blob

var aBlob = new Blob( array, options );

array

是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings会被编码为UTF-8。

options

是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性:

type,默认值为 "",它代表了将会被放入到blob中的数组内容的MIME类型。

endings,默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个: "native",代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者 "transparent",代表会保持blob中保存的结束符不变 

生成ArrayBuffer

var arrayBuffer=new ArrayBuffer(length);

length

要创建的 ArrayBuffer 的大小,单位为字节。

一个指定大小的 ArrayBuffer 对象,其内容被初始化为 0。

字符串blob

var aBlob=new Blob(['春']);
console.log(aBlob);//Blob(3) {size: 3, type: ""}
var bBlob=new Blob(['a']);
console.log(bBlob);//Blob(1) {size: 1, type: ""}

从我的第一篇文章中可以知道一个中文的UTF-8占三个字节,原始的ASCll码只占用一个字节,

从上面的结果可以就可以验证这一点。

创建ArrayBuffer对象

const buffer = new ArrayBuffer(3);
console.log(buffer.byteLength);//3

判断是否是视图实例(类型数组对象或 DataView 对象)

console.log(ArrayBuffer.isView(new Int8Array()));// true
console.log(ArrayBuffer.isView(new Uint32Array(3))); //true
console.log(ArrayBuffer.isView(new Blob()));//false;

操作ArrayBuffer

类型数组对象操作

创建了一个 4字节的缓冲区,并使用一个Unit8Array(视图实例)来引用它。ArrayBuffer表示了一段内存,但是却没有规定如何分隔里面的内容。比如用Unit8Array引用就表示8位一分隔,Unit16Array表示16位一分隔。

var buffer=new ArrayBuffer(4);
console.log(buffer);//ArrayBuffer(4) {};创建一个4个字节的区域,但是里面并没有内容;
var bytes = new Uint8Array( buffer );//ArrayBuffer 转换为 TypedArray(类数组对象);
var Int=new Uint16Array(buffer);
console.log(bytes);//Uint8Array(4) [0, 0, 0, 0];给4个字节区域用Unit8Array填充内容;
console.log(Int);//Uint16Array(2) [0, 0];4个字节,所以Uint16Array只有2个因为每个Uint16Array占2个字节

这个也就是我第三篇文章中ArrayBuffer转base64操作所用的方法。

DataView操作

var buffer= new ArrayBuffer(16);
var view= new DataView(buffer);
view.setUint8(1,20);//写
view.getUint8(1);//读20

dataview.getUint8(byteOffset [, littleEndian])

参数解析:

(1).byteOffset:必需,从哪个字节开始读取数据,0表示第一个字节,以此类推。

(2).littleEndian:可选,布尔值,规定是大端字节序还是小端字节序;true表示小端字节序,省略或者false表示大端字节序。

总结:计算机默认使用小端字节序,所以使用DataView读取Unit16Array的时候要使用view.getUint16(0,true)。

区别:类数组和DataView操作的区别在于,类数组操作会有字节序问题,而DataView可以指定字节序。

类数组对象转ArrayBuffer

var bytes




    
 = new Uint8Array([1,2,3]);
var buf=bytes.buffer;
console.log(buf);//ArrayBuffer(3) {};
var bytes = new Uint8Array([1,2,2,3]);//类数组对象
var buf=bytes.buffer;//转成ArrayBuffer对象;ArrayBuffer(4) {};
var ui8 = new Uint8Array(buf);
console.log(ui8);//Uint8Array(4) [1, 2, 2, 3];
var ui16 = new Uint16Array(buf);
console.log(ui16);//Uint16Array(2) [513, 770])
var view=new DataView(buf);
console.log(view.getUint8(0));//1
console.log(view.getUint16(0,true));//513 

1, 2, 2,3 (十进制)

 00000001, 00000010, 00000010,00000011 (二进制)

 513,770(十进制)

1000000001,1100000010(二进制)

上面可以看出513这个 2 字节的数据,其实是把 12 这两个挨着的 1 字节的数据,以 倒序 方式拼接在一起的。也就是字节序。

Blob转ArrayBuffer

//第一种方法
var blob=new Blob(['春节']),fileReader=new FileReader();
fileReader.onload=function(e){
    console.log(this.result);//ArrayBuffer(6) {}
fileReader.readAsArrayBuffer(blob);
//第二种方法(有兼容性问题)
var blob=new Blob(['春节']);
blob.arrayBuffer().then(res=>{console.log(res)})

ArrayBuffer转Blob

var blob=new Blob(['春节']),fileReader=new FileReader(),buffer;
fileReader.onload=function(e){
    console.log(this.result);//ArrayBuffer(6) {}
    buffer=this.result;
    var newBlob=new Blob([buffer]);
    newBlob.text().then(res=>{console.log(res)})//春节
fileReader.readAsArrayBuffer(blob);

Blob应用

1.Data URL:表示base64 编码的图像数据。

可以看我上一篇文章有blob转base64显示的示例。

2.HTTP URL:表示从服务器上获取图片。

//掘金收藏集图片
<img data-v-391f1edb="" src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-assets/v3/static/img/collections.945b9ae.png~tplv-t2oaga2asx-image.image" class="icon">

3.Object URL:用来代表存储在浏览器内存中的 FileBlob 对象。Object URL 可以由createObjectURL API 来创建,并由 revokeObjectURL API 释放。

    // 掘金首页收藏集图片
    fetch('https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-assets/v3/static/img/collections.945b9ae.png~tplv-t2oaga2asx-image.image',{
        method: 'get',
        responseType: 'blob'
    }).then(res =>res.blob()).then(res=> {
        var herf=URL.createObjectURL(res);
        console.log(href);//blob:https://juejin.im/c6322385-2ed5-47de-8dd4-9faa5acd4eb4
        //替换相应的url也能够显示图片
        URL.revokeObjectURL(herf);//释放
    //<img data-v-391f1edb="" src="blob:https://juejin.im/c6322385-2ed5-47de-8dd4-9faa5acd4eb4" class="icon">

获取上传 Input 中的图片对象 File

 图片通过 Canvas 转换压缩,这里会用到的 Canvas 的 drawImage 以及 toDataURL 这两个 Api,一个调节图片的分辨率的,一个是调节图片压缩质量。

//掘金首页收藏集图片;

//为了演示,用获取的blob代替从input对象获取的File对象 var image = new Image(); //新建一个img标签; fetch('p1-jj.byteimg.com/tos-cn-i-t2…', { method: 'get', responseType: 'blob' }).then(res => res.blob()).then(res => { console.log(res);//Blob(833) {size: 833, type: "image/png"} var href = URL.createObjectURL(res); image.src = href; image.onload = function() { compress(image, 'png', 92,100); //canvas压缩百分之92;图片保存原有大小 function compress(image, type, quality,targetPercent) { let canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); // 定义 canvas 大小,也就是压缩后下载的图片大小 let imageWidth = image.width; //压缩后图片的大小 let imageHeight = image.height; canvas.width = imageWidthtargetPercent/100; canvas.height = imageHeighttargetPercent/100; context.drawImage(image, 0, 0,canvas.width,canvas.height); var compressImg = canvas.toDataURL(image/${type}, quality / 100); console.log(compressImg); //base64数据; canvas.toBlob(function(blob) {//canvas转blob; console.log(blob);//Blob(725) {size: 725, type: "image/png"}

toDataURL() 方法,该方法接收 typeencoderOptions 两个可选参数。

其中 type 表示图片格式,默认为 image/png。而 encoderOptions 用于表示图片的质量,在指定图片格式为 image/jpegimage/webp 的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92,其他参数会被忽略。

图片压缩到指定大小

 fetch('https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-assets/v3/static/img/collections.945b9ae.png~tplv-t2oaga2asx-image.image', {
        method: 'get',
        responseType: 'blob'
    }).then(res => res.blob()).then(res => {
        console.log(res.size);//Blob(833) {size: 833, type: "image/png"}
       var image = new Image();
        var href = URL.createObjectURL(res);
        image.src = href;        image.onload = function() {
            compress(image,res,1); //将流压缩到3M以内        };
//base64转blob;
  function dataURLtoBlob(dataURI) {
    var byteString = atob(dataURI.split(',')[1]);
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    return new Blob([ab], {type: mimeString});
	function compress(image,blob,size) {
        //blob原始的流 size要压缩的流的大小
        let oldSize=blob.size;
        if(oldSize>size*1024*1024){//大于1M才压缩
         let canvas = document.createElement('canvas');
         let context = canvas.getContext('2d');
        // 定义 canvas 大小,也就是压缩后下载的图片大小
        let imageWidth = image.width; //原始图片的大小
        let imageHeight = image.height;
        let targetPercent=(size*1024*1024/oldSize).toFixed(2);
        canvas.width = imageWidth*targetPercent;
        canvas.height = imageHeight*targetPercent;
        context.drawImage(image, 0, 0,canvas.width,canvas.height);
        var compressImg = canvas.toDataURL(blob.type,1);
        return dataURLtoBlob(compressImg);
        }else{
	return blob;
const file = new File(["a".repeat(1000000)], "test.txt");
const chunkSize = 40000;
const url = "https://httpbin.org/post";
async function chunkedUpload() {
  for (let start = 0; start < file.size; start += chunkSize) {
      const chunk = file.slice(start, start + chunkSize + 1);
      const fd = new FormData();
      fd.append("data", chunk);
      await fetch(url, { method: "post", body: fd }).then((res) =>
        res.text()
var url = 'https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-assets/v3/static/img/collections.945b9ae.png~tplv-t2oaga2asx-image.image'; //文件下载地址fetch(url, {    method: 'get',    responseType: 'blob'}).then(res => res.blob()).then(res => {    var url = window.URL.createObjectURL(res);    var a = document.createElement("a");    a.href = url;    a.download = "测试";    a.click();    a.remove();    window.URL.revokeObjectURL(url);})
  • 你不知道的 Blob
  • 前端通过Blob实现文件下载
  • MDN | Blob
  • JavaScript