Web Api中的Blob到底是个啥?

前言

有幸在一个后台上传大文件的需求中了解到了Blob,其实真正接触Blob对象是在下载电影的时候,现在很多video标签的src路径是blob格式,当时只知道是流媒体,Blob还带着一层面纱,那么Blob到底是个啥,这里来浅谈一下~

一、Blob对象

Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。
File 接口基于 Blob,继承了 blob 的功能并将其扩展以支持用户系统上的文件。

说人话:简单来讲,就是Blob可以将文件换成二进制格式,并对这个为二进制文件进行剪切和拼接操作,也是目前js唯一可以操作二进制的方式。

1、创建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 中保存的结束符不变

举例:

var b1 = 'hey!'; // DOMString 
var b2 = '123';
var aBlob = new Blob([b1], {type:'text/html'} );
console.log(aBlob);
//Blob {size: 35, type: 'text/html'}

实例方法:

Blob实例对象有以下方法:不再一一详述,大家感兴趣可以点击方法名去文档做了解

  • slice():返回一个新的 Blob 对象,包含了源 Blob 对象中指定范围内的数据。
  • stream():返回一个能读取 blob 内容的 ReadableStream。
  • text():返回一个 Promise 对象且包含 blob 所有内容的 UTF-8 格式的 USVString。
  • arrayBuffer():返回一个 Promise 对象且包含 blob 所有内容的二进制格式的 ArrayBuffer

2、创建blob URL

平时我们常见到的还是blob URL
Blob url 是指向存储在浏览器缓存或磁盘中的blob的一个引用。

//格式如:
blob:https://www.jianshu.com/u/685589ccbc2a

Blob URL可以通过URL.createObjectURL(blob)创建。在绝大部分场景下,我们可以像使用Http协议的URL一样,使用Blob URL。常见的场景有:作为文件的下载地址和作为图片资源地址。

举例:

给上传图片创建一个Blob URL




    



    
    
image中生成的blob Url

注:在每次调用 createObjectURL() 方法时,都会创建一个新的 URL 对象,即使你已经用相同的对象作为参数创建过。当不再需要这些 URL 对象时,每个对象必须通过调用 URL.revokeObjectURL() 方法来释放,清除占用内存。
浏览器在 document 卸载的时候,会自动释放它们,但是为了获得最佳性能和内存使用状况,你应该在安全的时机主动释放掉它们。

二、常用场景

当我们上传大文件时,传输速度过慢,如果中间断开链接,也会导致传输文件丢失,这时常用blob对象来进行分片上传
分片上传主要是用Blob对象的slice方法将原文件剪切成碎片,然后依次将碎片上传。

1、slice方法

Blob.slice() 方法用于创建一个包含源 Blob的指定字节范围内的数据的新 Blob 对象。
前边提到,Blob 对象是不可改变的。我们不能直接在一个 Blob 中更改数据,但是我们可以对一个 Blob 进行分割,从其中创建新的 Blob 对象,将它们混合到一个新的 Blob 中。这种行为类似于 JavaScript 字符串:我们无法更改字符串中的字符,但可以创建新的更正后的字符串。

var blob = instanceOfBlob.slice([start [, end [, contentType]]]};

参数:

  • start:可选

    • 这个参数代表 Blob里的下标,表示第一个会被会被拷贝进新的 Blob的字节的起始位置。
    • 如果你传入的是一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。举例来说,-10 将会是 Blob的倒数第十个字节。
    • 它的默认值是 0,如果你传入的 start 的长度大于源 Blob 的长度,那么返回的将会是一个长度为 0 并且不包含任何数据的一个 Blob对象。
  • end:可选

    • 这个参数代表 Blob里的下标,这个下表-1的对应字节将会呗拷贝进新的Blob的最后一个字节
    • 如果你传入一个负数,那么这个偏移量将会从数据的末尾从后往前开始计算。举例来说,-10 将会是 Blob的倒数第十个字节。
    • 它的默认值是他的原始长度(size)。
  • contentType:可选

    • 给新的Blob赋予一个新的文档类型。这将会把它的 type 属性设为被传入的值。它的默认值是 一个空的字符串。

举例

    var data = "12345678";
    var blob1 = new Blob([data]);
    var blob2 = blob1.slice(0,4);
    
    console.log(blob1);  //输出:Blob {size: 8, type: ""}
    console.log(blob2);  //输出:Blob {size: 4, type: ""}

2、分片上传

前面已经说过,File接口基于 Blob,继承了 blob 的功能并将其扩展以支持用户系统上的文件。因此我们可以调用File的slice方法对大文件进行分片长传。代码如下:

注:file.slice()返回的是blob对象

function uploadFile(file) {
  var chunkSize = 1024 * 1024;   // 每片1M大小
  var totalSize = file.size;//文件总长度
  var chunksNum = Math.ceil(totalSize / chunkSize);  //分片总数
  var index = 0;  // 分片的索引标记,记录是第几片
  
  var reader = new FileReader();
  reader.onload = function(e) {
    var xhr = new XMLHttpRequest();
    xhr.open("POST","http://xxxx/upload?fileName="+file.name);
    xhr.overrideMimeType("application/octet-stream");
    
    xhr.onreadystatechange = function() {
      if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        ++index;
        if(index === chunksNum) {
          alert("上传完成");
        } else if(offset === chunksNum-1){
          blob = file.slice(index*chunkSize, totalSize);   // 上传最后一片
          reader.readAsBinaryString(blob);
        } else {
          blob = file.slice(index*chunkSize, (index+1)*chunkSize); 
          reader.readAsBinaryString(blob);
        }
      }else {
        alert("上传出错");
      }
    }
    
    if(xhr.sendAsBinary) {
      xhr.sendAsBinary(e.target.result);   // e.target.result是此次读取的分片二进制数据
    } else {
      xhr.send(e.target.result);
    }
  }
   var blob = file.slice(index, chunkSize);
   reader.readAsBinaryString(blob);//开始上传时读取第一片文件,第一次触发reader.onload
}

这个代码中用到了FileReader对象中的readAsBinaryString方法来读取blob文件片,并触发onload事件监听文件读取完成的时间节点,同时onload返回的 result 属性包含所读取文件原始二进制格式,也就是最终上传的文件内容。

注:

使用FileReader时,一定记住readAsBinaryString方法和onload成对使用,没有readAsBinaryString方法,则无法触发onload。

三、相关知识

1、【FileReader】
2、【URL.createObjectURL()】

你可能感兴趣的:(Web Api中的Blob到底是个啥?)