利用Blob进行文件上传的完整步骤
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
data url
- blob url的长度一般比较短,但data url因为直接存储图片base64编码后的数据,往往很长,如上图所示,浏览器在显示data url时使用了省略号(…)。当显式大图片时,使用blob url能获取更好的可能性。
- blob url可以方便的使用xmlhttprequest获取源数据,比如设置xmlhttprequest返回的数据类型为blob
- blob url 只能在当前应用内部使用,把blob url复制到浏览器的地址栏中,是无法获取数据的。data url相比之下,就有很好的移植性,可以在任意浏览器中使用。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。