利用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 相关文章推荐
JavaScript Undefined,Null类型和NaN值区别
Oct 22 Javascript
Extjs中DisplayField的日期或者数字格式化扩展
Sep 03 Javascript
jqTransform form表单美化插件使用方法
Jul 05 Javascript
js 获取坐标 通过JS得到当前焦点(鼠标)的坐标属性
Jan 04 Javascript
杨氏矩阵查找的JS代码
Mar 21 Javascript
js实现倒计时时钟的示例代码
Dec 17 Javascript
解决前端跨域问题方案汇总
Nov 20 Javascript
jquery.cookie.js的介绍与使用方法
Feb 09 Javascript
Boostrap栅格系统与自己额外定义的媒体查询的冲突问题
Feb 19 Javascript
json字符串传到前台input的方法
Aug 06 Javascript
jQuery使用each遍历循环的方法
Sep 19 jQuery
ES6知识点整理之Proxy的应用实例详解
Apr 16 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
MySQL数据库转移,access,sql server 转 MySQL 的图文教程
2007/09/02 PHP
PHP运行模式的深入理解
2013/06/03 PHP
PHP自带方法验证邮箱、URL、IP是否合法的函数
2016/12/08 PHP
关于php几种字符串连接的效率比较(详解)
2017/02/22 PHP
php实现数组纵向转横向并过滤重复值的方法分析
2017/05/29 PHP
JavaScript创建一个欢迎cookie弹出窗实现代码
2013/03/15 Javascript
JS实现鼠标经过好友列表中的好友头像时显示资料卡的效果
2014/07/02 Javascript
JS实现很酷的水波文字特效实例
2015/02/26 Javascript
简述Jquery与DOM对象
2015/07/10 Javascript
JS+DIV+CSS排版布局实现美观的选项卡效果
2015/10/10 Javascript
js密码强度检测
2016/01/07 Javascript
AngularJs  Using $location详解及示例代码
2016/09/02 Javascript
js实现的光标位置工具函数示例
2016/10/03 Javascript
浅谈Vue.js中的v-on(事件处理)
2017/09/05 Javascript
深入理解ES7的async/await的用法
2017/09/09 Javascript
node文件批量重命名的方法示例
2017/10/23 Javascript
从零开始搭建webpack+react开发环境的详细步骤
2018/05/18 Javascript
JS获取指定月份的天数两种实现方法
2018/06/22 Javascript
跨域解决之JSONP和CORS的详细介绍
2018/11/21 Javascript
vue项目前端知识点整理【收藏】
2019/05/13 Javascript
[02:12]DOTA2英雄基础教程 变体精灵
2013/12/16 DOTA
[00:53]2015国际邀请赛 中国区预选赛一触即发
2015/05/14 DOTA
Python 迭代器与生成器实例详解
2017/05/18 Python
人生苦短我用python python如何快速入门?
2018/03/12 Python
详解Python中的动态属性和特性
2018/04/07 Python
对python中xlsx,csv以及json文件的相互转化方法详解
2018/12/25 Python
python如何获取当前文件夹下所有文件名详解
2019/01/25 Python
Python实现对特定列表进行从小到大排序操作示例
2019/02/11 Python
用python实现名片管理系统
2020/06/18 Python
斯图尔特·韦茨曼鞋加拿大官网:Stuart Weitzman加拿大
2019/10/13 全球购物
初二物理教学反思
2014/01/29 职场文书
2014年信息中心工作总结
2014/12/17 职场文书
Goland使用Go Modules创建/管理项目的操作
2021/05/06 Golang
python实现A*寻路算法
2021/06/13 Python
nginx请求限制配置方法
2021/07/09 Servers
Python中的matplotlib绘制百分比堆叠柱状图,并为每一个类别设置不同的填充图案
2022/04/20 Python