利用Blob进行文件上传的完整步骤


Posted in Javascript onAugust 02, 2018

Blob

Blob,Binary Large Object的缩写,二进制类型的大对象,代表不可改变的原始数据

在计算机中,BLOB常常是数据库中用来存储二进制文件的字段类型。

Blob基本用法

Blob对象

Blob对象指的是字节序列,并且具有size属性,是字节序列中的字节总数,和一个type属性,它是小写的ASCII编码的字符串表示的媒体类型字节序列。

size:以字节数返回字节序列的大小。获取时,符合要求的用户代理必须返回一个FileReader或一个FileReaderSync对象可以读取的总字节数,如果Blob没有要读取的字节,则返回0 。
type:小写的ASCII编码字符串表示媒体类型Blob。在获取时,用户代理必须Blob以小写形式返回a类型的ASCII编码字符串,这样当它转换为字节序列时,它是可解析的MIME类型,或者是空字符串(0字节)如果是类型无法确定。

构造函数

创建blob对象本质上和创建一个其他对象的方式是一样的,都是使用Blob() 的构造函数来进行创建。 构造函数接受两个参数:

第一个参数为一个数据序列,格式可以是ArrayBuffer, ArrayBufferView, Blob, DOMString
第二个参数是一个包含以下两个属性的对象

  • type: MIME的类型,
  • endings: 决定第一个参数的数据格式。默认值为"transparent",用于指定包含行结束符n的字符串如何被写入。 它是以下两个值中的一个: "native",表示行结束符会被更改为适合宿主操作系统文件系统的换行符; "transparent",表示会保持blob中保存的结束符不变。
var data1 = "a";
 var blob1 = new Blob([data1]);
 console.log(blob1); //输出:Blob {size: 1, type: ""}
 
 var debug = {hello: "world"};
 var blob = new Blob([JSON.stringify(debug, null, 2)],{type : 'application/json'});
 console.log(blob) // 输出 Blob(22) {size: 22, type: "application/json"}
 
 // 创建一个8字节的ArrayBuffer,在其上创建一个每个数组元素为2字节的“视图”
 var abf = new ArrayBuffer(8)
 var abv = new Int16Array(abf)
 var bolb_ArrayBuffer = new Blob(abv, {type : 'text/plain'})
 console.log(bolb_ArrayBuffer) //输出 Blob(4) {size: 4, type: "text/plain"}

slice方法

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

slice(start, end, contentType)

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用于文件分片上传

  • 分片与并发结合,将一个大文件分割成多块,并发上传,极大地提高大文件的上传速度。
  • 当网络问题导致传输错误时,只需要重传出错分片,而不是整个文件。另外分片传输能够更加实时的跟踪上传进度。

分片上传逻辑如下:

获取要上传文件的File对象,根据chunk(每片大小)对文件进行分片
通过post方法轮循上传每片文件,其中url中拼接querystring用于描述当前上传的文件信息;post body中存放本次要上传的二进制数据片段
接口每次返回offset,用于执行下次上传

initUpload();

//初始化上传
function initUpload() {
 var chunk = 100 * 1024; //每片大小
 var input = document.getElementById("file"); //input file
 input.onchange = function (e) {
  var file = this.files[0];
  var query = {};
  var chunks = [];
  if (!!file) {
   var start = 0;
   //文件分片
   for (var i = 0; i < Math.ceil(file.size / chunk); i++) {
    var end = start + chunk;
    chunks[i] = file.slice(start , end);
    start = end;
   }
   
   // 采用post方法上传文件
   // url query上拼接以下参数,用于记录上传偏移
   // post body中存放本次要上传的二进制数据
   query = {
    fileSize: file.size,
    dataSize: chunk,
    nextOffset: 0
   }

   upload(chunks, query, successPerUpload);
  }
 }
}

// 执行上传
function upload(chunks, query, cb) {
 var queryStr = Object.getOwnPropertyNames(query).map(key => {
  return key + "=" + query[key];
 }).join("&");
 var xhr = new XMLHttpRequest();
 xhr.open("POST", "http://xxxx/opload?" + queryStr);
 xhr.overrideMimeType("application/octet-stream");
 
 //获取post body中二进制数据
 var index = Math.floor(query.nextOffset / query.dataSize);
 getFileBinary(chunks[index], function (binary) {
  if (xhr.sendAsBinary) {
   xhr.sendAsBinary(binary);
  } else {
   xhr.send(binary);
  }

 });

 xhr.onreadystatechange = function (e) {
  if (xhr.readyState === 4) {
   if (xhr.status === 200) {
    var resp = JSON.parse(xhr.responseText);
    // 接口返回nextoffset
    // resp = {
    //  isFinish:false,
    //  offset:100*1024
    // }
    if (typeof cb === "function") {
     cb.call(this, resp, chunks, query)
    }
   }
  }
 }
}

// 每片上传成功后执行
function successPerUpload(resp, chunks, query) {
 if (resp.isFinish === true) {
  alert("上传成功");
 } else {
  //未上传完毕
  query.offset = resp.offset;
  upload(chunks, query, successPerUpload);
 }
}

// 获取文件二进制数据
function getFileBinary(file, cb) {
 var reader = new FileReader();
 reader.readAsArrayBuffer(file);
 reader.onload = function (e) {
  if (typeof cb === "function") {
   cb.call(this, this.result);
  }
 }
}

Blob URL

blob协议的url使用时就像平时使用的url一样,可以作为图片请求地址,也可以作为文件请求地址。格式:

blob:http://XXX

  • URL.createObjectURL(blob) 创建链接
  • URL.revokeObjectURL(url)

下面是一个下载文件的示例,直接调用即可实现文件下载

// file是要下载的文件(blob对象)
downloadHandler: function (file, fileName) {
 let link = document.createElement('a')
 link.href = window.URL.createObjectURL(file)
 link.download = fileName
 link.click()
 window.URL.revokeObjectURL(link.href)
 if (navigator.userAgent.indexOf('Firefox') > -1) {
 const a = document.createElement('a')
 a.addEventListener('click', function (e) {
  a.download = fileName
  a.href = URL.createObjectURL(file)
 })
 let e = document.createEvent('MouseEvents')
 e.initEvent('click', false, false)
 a.dispatchEvent(e)
 }
}

在从后台获取的数据接口中把返回类型设置为blob

var x = new XMLHttpRequest();
x.responseType = 'blob';  // 返回一个blob对象

Blob URL和Data URL的区别

Blob URL

利用Blob进行文件上传的完整步骤

Data URL

利用Blob进行文件上传的完整步骤

  • Blob URL的长度一般比较短,但Data URL因为直接存储图片base64编码后的数据,往往很长,如上图所示,浏览器在显示Data URL时使用了省略号(…)。当显式大图片时,使用Blob URL能获取更好的可能性。
  • Blob URL可以方便的使用XMLHttpRequest获取源数据,比如设置XMLHttpRequest返回的数据类型为blob
  • Blob URL 只能在当前应用内部使用,把Blob URL复制到浏览器的地址栏中,是无法获取数据的。Data URL相比之下,就有很好的移植性,可以在任意浏览器中使用。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JS array 数组详解
Mar 22 Javascript
js实现简单排列组合的方法
Jan 27 Javascript
Angular.js回顾ng-app和ng-model使用技巧
Apr 26 Javascript
微信小程序 tabs选项卡效果的实现
Jan 05 Javascript
微信小程序中的onLoad详解及简单实例
Apr 05 Javascript
总结4个方面优化Vue项目
Feb 11 Javascript
node.js中express模块创建服务器和http模块客户端发请求
Mar 06 Javascript
JavaScript函数式编程(Functional Programming)高阶函数(Higher order functions)用法分析
May 22 Javascript
基于jquery实现的tab选项卡功能示例【附源码下载】
Jun 10 jQuery
JavaScript对象原型链原理详解
Feb 05 Javascript
Vue组件化开发之通用型弹出框的实现
Feb 28 Javascript
nuxt.js添加环境变量,区分项目打包环境操作
Nov 06 Javascript
vue.js图片转Base64上传图片并预览的实现方法
Aug 02 #Javascript
vue组件横向树实现代码
Aug 02 #Javascript
利用Node.js批量抓取高清妹子图片实例教程
Aug 02 #Javascript
在微信小程序里使用watch和computed的方法
Aug 02 #Javascript
在小程序中使用Echart图表的示例代码
Aug 02 #Javascript
node.js读取Excel数据(下载图片)的方法示例
Aug 02 #Javascript
Vue-cli配置打包文件本地使用的教程图解
Aug 02 #Javascript
You might like
PHP 实现多服务器共享 SESSION 数据
2009/08/15 PHP
php 无限分类的树类代码
2009/12/03 PHP
PHP读取XML值的代码(推荐)
2011/01/01 PHP
Laravel 登录后清空COOKIE的操作方法
2019/10/14 PHP
Javascript中call的两种用法实例
2013/12/13 Javascript
文本框文本自动补全效果示例分享
2014/01/19 Javascript
js监听鼠标点击和键盘点击事件并自动跳转页面
2014/09/24 Javascript
jQuery幻灯片带缩略图轮播效果代码分享
2015/08/17 Javascript
利用vue实现模态框组件
2016/12/19 Javascript
element-ui 时间选择器限制范围的实现(随动)
2019/01/09 Javascript
详解vue几种主动刷新的方法总结
2019/02/19 Javascript
详解vue-cli 脚手架 安装
2019/04/16 Javascript
微信小程序canvas分享海报功能
2019/10/31 Javascript
JS实现容器模块左右拖动效果
2020/01/14 Javascript
微信小程序实现上传多个文件 超过10个
2020/03/30 Javascript
vue3.0中友好使用antdv示例详解
2021/01/05 Vue.js
[03:55]显微镜下的DOTA2特别篇——430灰烬之灵神级操作
2014/06/24 DOTA
[01:32]DOTA2 2015国际邀请赛中国区预选赛第四日战报
2015/05/29 DOTA
python使用clear方法清除字典内全部数据实例
2015/07/11 Python
Django日志模块logging的配置详解
2017/02/14 Python
浅谈tensorflow中几个随机函数的用法
2018/07/27 Python
Python解析、提取url关键字的实例详解
2018/12/17 Python
PyTorch的深度学习入门教程之构建神经网络
2019/06/27 Python
python retrying模块的使用方法详解
2019/09/25 Python
详解Python可视化神器Yellowbrick使用
2019/11/11 Python
python中JWT用户认证的实现
2020/05/18 Python
医学院毕业生自荐信
2013/11/08 职场文书
培训主管的岗位职责
2013/11/23 职场文书
2014年档案管理员工作总结
2014/12/01 职场文书
实习单位意见
2015/06/04 职场文书
投诉书格式范本
2015/07/02 职场文书
青年干部培训班学习心得体会
2016/01/06 职场文书
原生CSS实现文字无限轮播的通用方法
2021/03/30 HTML / CSS
python实现过滤敏感词
2021/05/08 Python
Python深度学习之Pytorch初步使用
2021/05/20 Python
windows安装python超详细图文教程
2021/05/21 Python