zoukankan      html  css  js  c++  java
  • 【转】JS中的Blob对象

    前段时间研究二进制流图片展示遇到了Blob对象,在这里做一下笔记。

    在一般的Web开发中,很少会用到Blob,但Blob可以满足一些场景下的特殊需求。Blob,Binary Large Object的缩写,代表二进制类型的大对象。Blob的概念在一些数据库中有使用到,例如,MYSQL中的BLOB类型就表示二进制数据的容器。在Web中,Blob类型的对象表示不可变的类似文件对象的原始数据,通俗点说,就是Blob对象是二进制数据,但它是类似文件对象的二进制数据,因此可以像操作File对象一样操作Blob对象,实际上,File继承自Blob。

    Blob基本用法

    创建

    可以通过Blob的构造函数创建Blob对象:
    Blob(blobParts[, options])
    参数说明:
    blobParts: 数组类型, 数组中的每一项连接起来构成Blob对象的数据,数组中的每项元素可以是ArrayBuffer(二进制数据缓冲区), ArrayBufferView,Blob,DOMString。或其他类似对象的混合体。
    options: 可选项,字典格式类型,可以指定如下两个属性:

    • type,默认值为"",它代表了将会被放入到blob中的数组内容的MIME类型。
    • endings, 默认值为"transparent",用于指定包含行结束符 的字符串如何被写入。 它是以下两个值中的一个: "native",表示行结束符会被更改为适合宿主操作系统文件系统的换行符; "transparent",表示会保持blob中保存的结束符不变。
      举个栗子:
    var data1 = "a";
        var data2 = "b";
        var data3 = "<div style='color:red;'>This is a blob</div>";
        var data4 = { "name": "abc" };
    
        var blob1 = new Blob([data1]);
        var blob2 = new Blob([data1, data2]);
        var blob3 = new Blob([data3]);
        var blob4 = new Blob([JSON.stringify(data4)]);
        var blob5 = new Blob([data4]);
        var blob6 = new Blob([data3, data4]);
    
        console.log(blob1);  //输出:Blob {size: 1, type: ""}
        console.log(blob2);  //输出:Blob {size: 2, type: ""}
        console.log(blob3);  //输出:Blob {size: 44, type: ""}
        console.log(blob4);  //输出:Blob {size: 14, type: ""}
        console.log(blob5);  //输出:Blob {size: 15, type: ""}
        console.log(blob6);  //输出:Blob {size: 59, type: ""}

    size代表Blob 对象中所包含数据的字节数。这里要注意,使用字符串和普通对象创建Blob时的不同,blob4使用通过JSON.stringify把data4对象转换成json字符串,blob5则直接使用data4创建,两个对象的size分别为14和15。blob4的size等于14很容易理解,因为JSON.stringify(data4)的结果为:"{"name":"abc"}",正好14个字节(不包含最外层的引号)。blob5的size等于15是如何计算而来的呢?实际上,当使用普通对象创建Blob对象时,相当于调用了普通对象的toString()方法得到字符串数据,然后再创建Blob对象。所以,blob5保存的数据是"[object Object]",是15个字节(不包含最外层的引号)。

    slice方法

    Blob对象有一个slice方法,返回一个新的Blob对象,包含了源Blob对象中制定范围内的数据。
    参数说明:

    start: 可选,代表 Blob 里的下标,表示第一个会被会被拷贝进新的 Blob 的字节的起始位置。如果传入的是一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。

    end: 可选,代表的是 Blob 的一个下标,这个下标-1的对应的字节将会是被拷贝进新的Blob 的最后一个字节。如果你传入了一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。

    contentType: 可选,给新的 Blob 赋予一个新的文档类型。这将会把它的 type 属性设为被传入的值。它的默认值是一个空的字符串。
    举个栗子:

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

    通过slice方法,从blob1中创建出一个新的blob对象,size等于3。

    Blob对象能够添加到表单中,作为上传数据使用:

     
    const content = '<a id="a"><b id="b">hey!</b></a>';
    const blob = new Blob([content], {type: 'text/xml'});
    
    formData.append('webmasterfile', blob);

    Blob使用场景

    分片上传

    前面已经说过,File继承字Blob,因此我们可以调用slice方法对大文件进行分片上传。代码:

     
    function uploadFile(file) {
      var chunkSize = 1024 * 1024; //每片1M大小
      var totalSize = file.size;
      var chunkQuantity = Math.ceil(totalSize/chunkSize); //分片总数
      var offset = 0; //偏移量
    
      var reader = new FileReader();
      reader.onload = function(e) {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", url);
        xhr.overrideMineType("application/octet-stream");
        
        xhr.onreadstatechange = function() {
          if(xhr.readyState === 4 && xhr.status ===200) {
            ++offset;
            if(offset === chunkQuantity) {
              alerrt("上传完成");
            } else if(offset === chunckQuantity-1) {
              blob = file.slice(offset*chunkSize, totalSize);
              reader.readAsBinaryString(blob);
            } else {
              blob = file.slice(offset*chunkSize, (offset+1)*chunckSize);
              reader.readAsBinaryString(blob);
            }
          }else {
            alert("上传出错");
          }
        }
    
        if(xhr.sendAsBinary) {
          xhr.sendAsBinary(e.target.result);
        } else {
          xhr.send(e.target.result);
        }
      }
      var blob = file.slice(0, chunkSize);
      reader.readAsBinaryString(blob);
    }

    这段代码还可以进一步丰富,比如显示当前上传进度,使用多个XMLHttpRequest对象并行上传对象(需要传递分片数据得位置参数给服务器端)等。

    Blob URL

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

    • 文件下载地址
     
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
       <meta charset="UTF-8">
       <title>Blob Test</title.
      <script>  
        function createDownloadFile() {
          var content = "Blob Data";
          var blob = new Blob([content]);
          var link = document.getElementByTageName('a')[0];
          link.download = "file";
          link.href = URL.createObjectURL(blob);
        }
        window.onload = createDownloadFile;
      </script>
    </head>
    
    <body>
      <a>下载</a>
    </body>
    
    </html>

    点击下载按钮,浏览器将会下载一个名为file得文件,文件得内容是:Blob Data。通过Blob对象,我们在前端代码中就可以动态生成文件,提供 给浏览器下载。打开Chrome浏览器调试窗口,在Elements标签下可以看到生成得Blob URL:
    [图片上传失败...(image-130a5a-1551669191720)]

    • 图片资源地址
      为图片文件创建一个Blob URL,赋值给标签:
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Blob Test</title>
      <script>
        function handleFile(e) {
          var file = e.files[0];
          var blob = URL.createObjectURL(file);
          var img = document.getElementByTagName("img")[0];
          img.src = blob;
          img.onload = function(e) {
            URL.revokeObjectURL(this.src); //释放createObjectURL创建得对象
          }
        }
      </script>
    </head>
    
    <body>
      <input type="flie" accept="image/*" onchange="handleFile(this)" />
      <br/>
      <img style="200px;height:200px;">
    </body>
    
    </html>

    imput中选择得图片会在这里显示出来:

    [图片上传失败...(image-c20d1f-1551669191720)]
    同时,可以在Network标签栏,发现这个Blob URL得请求信息:
    [图片上传失败...(image-fa2288-1551669191720)]
    这个请求信息和我们平常使用Http URL获取得图片几乎完全一样。

    window.URL.revokeObjectURL()

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

    • 我们还可以使用Data URL加载图片资源:
     
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Blob Test</title>
      <script>
        function handleFile(e) {
          var file = e.files[0];
          var fileReader = new FileReader();
          var img = document.getElementByTagName("img")[0];
          fileReader.onload = function(e) {
            img.src = e.target.result;
          }
          fileReader.readAsDataURL(file);
        }
      </script>
    </head>
     
    <body> 
      <input type="file" accept="image/*" onchange="handleFile(this)" />
      </br>
      <img style="200px;height:200px;">
    </body>
      
    </html>

    Data URL对大家来说并不陌生,Web性能优化有一项措施:把小图片用base64编码直接嵌入到HTML文件中,实际就是利用了Data URL来获取图片数据。


    那么Blob URL和Data URL有什么区别呢?

    1. Blob URL得长度一般比较短,但Data URL因为直接存储图片base64编码后得数据,往往很长。当显示大图片时,使用Blob URL更优。
    2. Blob URL可以方便的使用XMLHttpRequest获取源数据,例如:
     
    var blobUrl = URL.createObkectURL(new Blob(['Test'], {type: 'text/plain'}));
    var xhr = new XMLHttpRequest();
    //如果是指xhr.responseType = 'blob',将返回一个Blob对象,而不是文本;
    //xhr.responseType = 'blob';
    xhr.onload = function() {
      alert(xhr.responseText);
    }
    xhr.open('get', blobUrl);
    xhr.send();

    对于Data URL, 并不是所有浏览器都支持通过XMLHttpRequest获取源数据的。

    1. Blob URL只能在当前应用内部使用,把Blob URL复制到浏览器的地址栏中,是无法获取数据的。Data URL相比之下,就有很好的移植性,你可以在任意浏览器使用。

    除了可以用作图片资源的网络地址,Blob URL也可以用作其他资源的网络地址,例如html文件、json文件等,为了保证浏览器能正确的解析Blob URL返回的文件类型,需要在创建Blob对象时指定相应的type:

    //创建HTML文件的Blob URL
    var data = "<div style='color:red;'This is a blob</div>";
    var blob = new Blob([data], {type: 'text/html'}); // 'application/json'
    var blobUrl = URL.createObjectURL(blob);


    from:https://www.jianshu.com/p/b322c2d5d778

  • 相关阅读:
    HDOJ 2095 find your present (2)
    HDOJ 2186 悼念512汶川大地震遇难同胞——一定要记住我爱你
    九度 1337 寻找最长合法括号序列
    九度 1357 疯狂地Jobdu序列
    HDOJ 1280 前m大的数
    九度 1343 城际公路网
    九度 1347 孤岛连通工程
    HDOJ 2151 Worm
    九度 1342 寻找最长合法括号序列II
    九度 1346 会员积分排序
  • 原文地址:https://www.cnblogs.com/xuan52rock/p/13519062.html
Copyright © 2011-2022 走看看