利用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 相关文章推荐
jquery blockUI 遮罩不能消失与不能提交的解决方法
Sep 17 Javascript
jquery实现图片左右间隔滚动特效(可自动播放)
May 08 Javascript
jQuery中;function($,undefined) 前面的分号的用处
Dec 17 Javascript
javascript文本模板用法实例
Jul 31 Javascript
jquery.form.js框架实现文件上传功能案例解析(springmvc)
May 26 Javascript
JavaScript获取select中text值的方法
Feb 13 Javascript
ES6新特性之模块Module用法详解
Apr 01 Javascript
React中上传图片到七牛的示例代码
Oct 10 Javascript
vue2.0与bootstrap3实现列表分页效果
Nov 28 Javascript
vue项目设置scrollTop不起作用(总结)
Dec 21 Javascript
怎样使你的 JavaScript 代码简单易读(推荐)
Apr 16 Javascript
防止Layui form表单重复提交的实现方法
Sep 10 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取进制余数函数代码
2012/01/19 PHP
php缩放gif和png图透明背景变成黑色的解决方法
2014/10/14 PHP
图文详解phpstorm配置Xdebug进行调试PHP教程
2016/06/13 PHP
CI框架(CodeIgniter)实现的数据库增删改查操作总结
2018/05/23 PHP
thinkphp5.0整合phpsocketio完整攻略(绕坑)
2018/10/12 PHP
Laravel5.7框架安装与使用学习笔记图文详解
2019/04/02 PHP
PHP设计模式之建造者模式(Builder)原理与用法案例详解
2019/12/12 PHP
随鼠标上下滚动的jquery代码
2013/12/05 Javascript
js实现可拖动DIV的方法
2013/12/17 Javascript
Javascript验证方法大全
2015/09/21 Javascript
javascript实现五星评分功能
2015/11/10 Javascript
javascript动态生成树形菜单的方法
2015/11/14 Javascript
jQuery使用经验小技巧(推荐)
2016/05/31 Javascript
关于javascript事件响应的基础语法总结(必看篇)
2016/12/26 Javascript
javascript 注释代码的几种方法总结
2017/01/04 Javascript
通过npm引用的vue组件使用详解
2017/03/02 Javascript
Bootstrap3.3.7导航栏下拉菜单鼠标滑过展开效果
2017/10/31 Javascript
Weex开发之地图篇的具体使用
2019/10/16 Javascript
解决node.js含有%百分号时发送get请求时浏览器地址自动编码的问题
2019/11/20 Javascript
使用Typescript和ES模块发布Node模块的方法
2020/05/25 Javascript
react使用antd表单赋值,用于修改弹框的操作
2020/10/29 Javascript
python切片及sys.argv[]用法详解
2018/05/25 Python
python3.4控制用户输入与输出的方法
2018/10/17 Python
python二元表达式用法
2019/12/04 Python
pytorch 求网络模型参数实例
2019/12/30 Python
Django2.1.7 查询数据返回json格式的实现
2020/12/29 Python
Python爬虫回测股票的实例讲解
2021/01/22 Python
CSS3制作hover下划线动画
2017/03/27 HTML / CSS
拉飞逸官网:Lafayette 148 New York
2020/07/15 全球购物
软件测试面试题
2015/10/21 面试题
毕业生就业推荐信范文
2013/12/01 职场文书
二年级体育教学反思
2014/01/15 职场文书
安全生产检讨书
2014/01/21 职场文书
校园标语大全
2014/06/19 职场文书
Python爬虫网络请求之代理服务器和动态Cookies
2022/04/12 Python
HTML静态页面获取url参数和UserAgent的实现
2022/08/05 HTML / CSS