Blob总结和使用案例

Blob介绍

Blob是对大数据块的不透明引用或者句柄。名字源于SQL数据库,表示“二进制大数据”(Binary Large Object)。在JavaScript中Blob通常表示二进制数据,但是不一定是大量数据。Blob是不透明的,我们可以对它执行的操作只有获取它的大小,MIME类型和将他切割成更小的Blob。——《JavaScript权威指南》

Blob 对象表示一个不可变、原始数据的类文件对象。Blob 表示的不一定是JavaScript原生格式的数据。——MDN

说人话就是Blob为一些JavaScript操作二进制数据的API提供了数据交换机制的支持。比如我们比较熟系的File接口就是基于Blob实现的,也是我们使用的Blob最多的方式,我们还可以借助Blob使用XMLHttpRequest从网络下载文件(二进制数据),并且Blob可以使用postMessage在窗口之间传递。

构造函数
var aBlob = new Blob( array, options );

返回一个新创建的 Blob 对象,其内容由参数中给定的数组串联组成。

  • array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings会被编码为UTF-8。
  • options 是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性:
    a. type,默认值为 “”,它代表了将会被放入到blob中的数组内容的MIME类型。
    b. endings,默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个: “native”,代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者 “transparent”,代表会保持blob中保存的结束符不变

构造一个html文件类型的Blob

var aFileParts = ['<a id="a"><b id="b">hey!</b></a>']; // 一个包含DOMString的数组
var oMyBlob = new Blob(aFileParts, {type : 'text/html'}); // 得到 blob
属性
  • Blob.size 只读
    Blob 对象中所包含数据的大小(字节)。
  • Blob.type 只读
    一个字符串,表明该 Blob 对象所包含数据的 MIME 类型。如果类型未知,则该值为空字符串。
方法
Blob.slice(start, end, contentType)

返回一个新的 Blob 对象,包含了源 Blob 对象中指定范围内的数据,start参数代表范围的开始下标,end代表复制范围的结束下标,contentType表示返回的Blob的文档类型。

let blob=new Blob(["这是保存到Blob中的文本数据"],{type:"application/text"})
let newBlob=blob.slice(0,5,"text/html");
Blob.stream()

返回一个能读取blob内容的 ReadableStream,使用 stream() 函数与其返回的ReadableStream对象,你将得到一些有趣的能力:

  1. 调用方法getReader(),在返回的stream上获取一个对象,通过ReadableStreamDefaultReader接口提 供的read()方法读取blob对象的方法。
  2. 调用返回stream对象的pipeTo()方法将blob对象的数据传输到可写流。
  3. 调用返回stream对象的tee()方法以准备可读流。该方法会返回一个数组,该数组包含两个新的 ReadableStream 对象,每个对象都会返回 Blob的内容。
  4. 调用返回stream对象的pipeThrough()方法,通过一个TransformStream对象或其它任意可读可写对传输流对象。
let blob=new Blob(["这是保存到Blob中的文本数据"],{type:"application/text"})
var stream = blob.stream();
let reader=stream.getReader()
reader.read().then(content=>/*处理读取到的数据*/console.log(content));
Blob.text()

返回一个promise且包含blob所有内容的UTF-8格式的 USVString。

let blob=new Blob(["这是保存到Blob中的文本数据"],{type:"application/text"})

var textPromise = blob.text();

blob.text().then(text => /* 执行的操作…… */console.log(text));

var text = await blob.text();
console.log(text)

本文后面要介绍另一种读取Blob的方法FileReader,两者都可以读取Blob的内容,区别如下:

  1. Blob.text() 返回的是一个 promise 对象,而 FileReader.readAsText() 是一个基于事件的 API。
  2. Blob.text() 总是使用 UTF-8 进行编码,而 FileReader.readAsText() 可以使用不同编码方式,取决于 blob 的类型和一个指定的编码名称。
Blob.arrayBuffer()

返回一个promise且包含blob所有内容的二进制格式的 ArrayBuffer

var bufferPromise = blob.arrayBuffer();

blob.arrayBuffer().then(buffer => /* 处理 ArrayBuffer 数据的代码……*/);

var buffer = await blob.arrayBuffer();

FileReader.readAsArrayBuffer() 这个方法与之类似,但 arrayBuffer() 返回一个 promise 对象,而不是像 FileReader 一样返回一个基于事件的 API。

Blob URL

我们可以创建一个URL指向Blob,从而使得它可以使用。
我们可以通过URL.createObjectURL()创建一个Blob URL,兼容的方法:

let getBlobURL=(window.URL&&URL.createObjectURL)||(window.webkitURL&&webkitURL.createObjectURL)||window.createObjectURL;

传递一个Blob对象给createObjectURL()会返回一个URL,实际上是一个形如blob://xxx的字符串,blob协议之后的部分是一个简单的blob在浏览器中保存的引用。
下面是一个使用Blob URL实现显示拖放的图片文件的功能:

 <!DOCTYPE html>
 <html>
     <head>
         <title>Blob</title>
         <style>
            #dragTarget{
                 border: solid black 2px;
                 width: 200px;
                 height: 200px;
                 display: flex;
                 align-items: center;
                 justify-content: center;
            }
            #dragTarget.active{
                 border: solid red 4px;
            }
         </style>  
     </head>
     <body>
         <div>
           <div  id="dragTarget">
               将文件拖放到此处
           </div>
         </div>
         <script>
            //禁用浏览器默认打开事件
            document.addEventListener('drop', function (e) {
                e.preventDefault()
            }, false)
            document.addEventListener('dragover', function (e) {
                e.preventDefault()
            }, false)
             let dragTarget=document.getElementById("dragTarget");
             dragTarget.ondragenter=function(e){
                 let types=e.dataTransfer.types;
                 //判断是否是文件类型
                 if(!types||(types.contains&&types.contains("Files"))
                 ||(types.indexOf&&types.indexOf("Files")!=-1)){
                       //触发高亮
                       dragTarget.classList.add('active');
                       dragTarget.textContent="松手显示图片"
                       return false;
                 }
             }
             dragTarget.ondragleave=function(){
                 dragTarget.classList.remove('active');
                 dragTarget.textContent="将文件拖放到此处"
             }
             dragTarget.ondragover=function(){return false};
             dragTarget.ondrop=function(e){
                 let files=e.dataTransfer.files;
                 //遍历插入图片
                 Array.prototype.forEach.call(files,file => {
                     let type=file.type;
                     //判断是否是图片类型
                     if(type.indexOf('image/')!=-1){
                         let img=document.createElement("img");
                         img.onload=function(){
                             this.width=100;
                             this.height=100;
                             document.body.append(this);
                             //要记得回收URL
                             URL.revokeObjectURL(file);
                         }
                         //创建URL并赋值给img的src属性
                         img.src=URL.createObjectURL(file);
                     }
                 });
                 //完成操作,移除高亮样式
                 dragTarget.classList.remove("active");
                 dragTarget.textContent="将文件拖放到此处"
                 return false;
             }
         </script>
     </body>
 </html>

文件下载

我们结合Blob URL和XMLHttpRequest可以实现文件从服务器下载功能。

let req=new XMLHttpRequest();
req.open("GET",url);
req.responseType="blob";
req.οnlοad=function(){
    let resBlob=this.response;
    resBlob.type = "application/octet-stream";
    //使用Blob创建URL
    let url=URL.createObjectURL(resBlob);
    let a=document.createElement("a");
    //将url赋值给a标签的href属性
    a.href=url;
    //下载的文件的文件名
    a.download="要下载的文件名称.扩展名";
    //触发click事件执行下载
    a.click();
     //要记得回收URL
    URL.revokeObjectURL(url);
}
req.send(null);

我们也可以本地构造一个html文件类型的Blob并下载到本地

let aFileParts = ['<a id="a"><b id="b">hey!</b></a>']; // 一个包含DOMString的数组
let oMyBlob = new Blob(aFileParts, {type : 'text/html'}); // 得到 blob
let a=document.createElement("a");
let url=URL.createObjectURL(oMyBlob);
//将url赋值给a标签的href属性
a.href=url;
//下载的文件的文件名
a.download="要下载的文件名称.html";
//触发click事件执行下载
a.click();
//要记得回收URL
URL.revokeObjectURL(url);

同理构造一个文本类型Blob并下载到本地

let resBlob=new Blob(["这是要放入Blob中的字符串数据"],{type:"application/text"});
let a=document.createElement("a");
let url=URL.createObjectURL(resBlob);
//将url赋值给a标签的href属性
a.href=url;
//下载的文件的文件名
a.download="要下载的文件名称.txt";
//触发click事件执行下载
a.click();
//要记得回收URL
URL.revokeObjectURL(url);

要记得回收BlobURL对象,因为这个对象不会被自动回收。

FileReader读取Blob

我们可以使用FileReader对象来读取Blob中的字节或者字符。FileReaderapi都是异步的,但是他在Worker中有对应的同步版本FileReaderSync
要使用FileReader首先要创建它的实例,然后为它添加事件处理函数onloadonerroronprogress等或者使用addEventListenter监听事件。FileReader对象还会触发loadstartloadendabort事件。
FileReader有4个读取Blob内容的方法:readAsText()readAsArrayBuffer()readAsDataURL()readAsBinaryString()。以上方法都接收Blob对象作为第一个参数,readAsText()方法还接收第二个可选参数指定文本的编码方式,默认是ASCIIUTF-8

  • 使用readAsText()方法的例子:
<div>
   <input type="file" onchange="readFile(this.files[0])" />
   <div id="content"></div>
</div>
<script>
function readFile(file){
    //创建FileReader对象
    let reader=new FileReader();
    //读取Blob,因为File对象为一个Blob对象的封装
    reader.readAsText(file);
    //添加onload事件处理函数
    reader.onload=function(){
        let text=reader.result;//获得读取结果
        let content=document.getElementById("content");
        content.innerHtml=text;
        //将结果写入到界面
        
        content.appendChild(document.createTextNode(text));
    }
    //添加onerror事件处理函数
    reader.onerror=function(error){
        console.log(error);
    }
}
</script>
  • 使用readAsArrayBuffer()方法读取的例子:
<div>
   <input type="file" onchange="typeFile(this.files[0])" />
</div>
<script>
function typeFile(file){
    //创建FileReader对象
    let reader=new FileReader();
    let typeArea=file.slice(0,4);//读取文件开头部分(前四个字节)
    //读取Blob,因为File对象为一个Blob对象的封装
    reader.readAsArrayBuffer(typeArea);
    //添加onload事件处理函数
    reader.onload=function(){
       let buffer=this.result;
       let view=new DataView(buffer);
       let type=view.getUint32(0,false);//以高位优先字节顺读取4个字节
       switch(type){
           case 0x89504E47:
                file.m_type="image/png";
                break;
           case 0x47494638:
                file.m_type="image/gif";
                break;
           case 0x25504446:
                file.m_type="application/pdf";
                break;
           case 0x504b0304:
                file.m_type="application/zip";
                break;    
       }
       console.log(file.name,file.m_type);
    }
    //添加onerror事件处理函数
    reader.onerror=function(error){
        console.log(error);
    }
}
</script>

最后

这篇文章是本人在开发中有一个点击按钮下载excel文件的需求,在查阅实现方式的过程中发现需要结合Blob来实现下载。所以就总结了一下Blob的基本概念和常用使用方法,并列举了应用案例。如有错误,还望指正。如果感觉还可以,欢迎点赞!

参考文献:
JavaScript权威指南
MDN web docs

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一拳小和尚LXY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值