利用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 相关文章推荐
Extjs学习笔记之三 extjs form更多的表单项
Jan 07 Javascript
jquery重新播放css动画所遇问题解决
Aug 21 Javascript
基于Jquery+Ajax+Json实现分页显示附效果图
Jul 30 Javascript
javascript实现仿IE顶部的可关闭警告条
May 05 Javascript
javascript实现列表滚动的方法
Jul 30 Javascript
Bootstrap Chart组件使用教程
Apr 28 Javascript
jQuery 特性操作详解及实例代码
Sep 29 Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
Nov 29 Javascript
React Native 真机断点调试+跨域资源加载出错问题的解决方法
Jan 18 Javascript
vue 插值 v-once,v-text, v-html详解
Jan 19 Javascript
D3.js的基础部分之数组的处理数组的排序和求值(v3版本)
May 09 Javascript
js实现简单五子棋游戏
May 28 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中HTTP方式下的Gzip压缩传输方法举偶
2007/02/15 PHP
thinkphp微信开发(消息加密解密)
2015/12/02 PHP
PHP生成和获取XML格式数据的方法
2016/03/04 PHP
PHP设计模式之观察者模式定义与用法分析
2019/04/04 PHP
js图片自动切换效果处理代码
2013/05/07 Javascript
分享9个最好用的JavaScript开发工具和代码编辑器
2015/03/24 Javascript
JavaScript组成、引入、输出、运算符基础知识讲解
2016/12/08 Javascript
快速实现jQuery多级菜单效果
2017/02/01 Javascript
浅谈$_FILES数组为空的原因
2017/02/16 Javascript
javascript获取指定区间范围随机数的方法
2017/09/08 Javascript
详解用Node.js写一个简单的命令行工具
2018/03/01 Javascript
vue中导出Excel表格的实现代码
2018/10/18 Javascript
js实现继承的方法及优缺点总结
2019/05/08 Javascript
vue 实现通过vuex 存储值 在不同界面使用
2019/11/11 Javascript
原生js实现购物车功能
2020/09/23 Javascript
[01:25]DOTA2自定义游戏灵园鬼域等你踏足
2015/10/30 DOTA
Python实现简单字典树的方法
2016/04/29 Python
Python使用wget实现下载网络文件功能示例
2018/05/31 Python
在python中实现调用可执行文件.exe的3种方法
2019/07/07 Python
Django Form and ModelForm的区别与使用
2019/12/06 Python
python实现百度OCR图片识别过程解析
2020/01/17 Python
python程序如何进行保存
2020/07/03 Python
使用darknet框架的imagenet数据分类预训练操作
2020/07/07 Python
秘鲁购物网站:Linio秘鲁
2017/04/07 全球购物
亚洲领先的旅游体验市场:Voyagin
2019/11/23 全球购物
外语专业毕业生自我评价分享
2013/10/05 职场文书
大学生冰淇淋店商业计划书
2014/01/14 职场文书
文明演讲稿范文
2014/05/12 职场文书
2014年巴西世界杯口号
2014/06/05 职场文书
销售团队激励口号
2014/06/06 职场文书
2014年学校教学工作总结
2014/12/06 职场文书
创先争优活动个人总结
2015/03/04 职场文书
2015年保安个人工作总结
2015/04/02 职场文书
《折线统计图》教学反思
2016/02/22 职场文书
如何用JavaScript实现一个数组惰性求值库
2021/05/05 Javascript
python ansible自动化运维工具执行流程
2021/06/24 Python