这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战
blob 二进制大对象
BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器。
创建Blob对象的方法有几种,可以调用Blob构造函数,还可以使用一个已有Blob对象上的slice()方法切出另一个Blob对象,还可以调用canvas对象上的toBlob方法。
第一次见到这个词是半年之前,那个时候居然没有听过blob,然后上网查了一下,巴拉巴拉一大堆,当时是不理解的。
看了前面的一系列API和对象,或许很多同学开始晕了,但是在一开始说到的blob对象,我们一直没有提到,如果本文不提及,显然是不合理的。毕竟作为File对象的爸爸,blob劳苦功高。上述的FileReader对象也可以操作blob对象。
Blob对象有两个只读属性:
- size:二进制数据的大小,单位为字节。
- type:二进制数据的MIME类型,全部为小写,如果类型未知,则该值为空字符串。
在Ajax操作中,如果xhr.responseType设为blob,接收的就是二进制数据。
Blob 构造函数生成blob对象
Blob构造函数,接受两个参数。第一个参数是一个包含实际数据的数组,第二个参数是数据的类型,这两个参数都不是必需的。数组元素可以是任意多个的ArrayBuffer,ArrayBufferView (typed array), Blob,或者 DOMString对象。 例如:
var arr = ['<h1>hello world</h1>'];
var blob = new Blob(arr, { "type" : "text/xml" }); // the blob
console.log(blob);
效果如下:
用JS在浏览器中创建下载文件
前端很多项目中,都有文件下载的需求,特别是JS生成文件内容,然后让浏览器执行下载操作(例如在线图片编辑、在线代码编辑、iPresst等)但受限于浏览器,很多情况下我们都只能给出个链接,让用户点击打开-》另存为。如下面这个链接:
<a href="file.js">file.js</a>
用户点击这个链接的时候,浏览器会打开并显示链接指向的文件内容,显然,这并没有实现我们的需求。HTML5中给a标签增加了一个download属性,只要有这个属性,点击这个链接时浏览器就不在打开链接指向的文件,而是改为下载(目前只有chrome、firefox和opera支持)。下载时会直接使用链接的名字来作为文件名,但是是可以改的,只要给download加上想要的文件名即可,如:download="not-a-file.js"。但是这样还不够,以上的方法只适合用在文件是在服务器上的情况。如果在浏览器端js生成的内容,想让浏览器进行下载要如何办到呢?DataURI可以实现这个效果,但是DataURI的文件类型被限制了,我们这里可以变通一下实现blob对象。
<a id="aLink">下载</a>
<script type="text/javascript">
function downloadFile (el, fileName, content) {
var aLink = document.querySelector(el);
var blob = new Blob([content]);
aLink.download = fileName;
aLink.href = URL.createObjectURL(blob);
}
document.querySelector('#aLink').addEventListener('click',function () {
downloadFile('#aLink', 'hello.txt', '<h1>hello world</h1>');
})
</script>
Blob对象的slice方法生成blob对象
Blob对象的slice方法,将二进制数据按照字节分块,返回一个新的Blob对象。
var newBlob = oldBlob.slice(startingByte, endindByte);
下面是一个使用XMLHttpRequest对象,将大文件分割上传的例子。
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
xhr.send(blobOrFile);
}
document.querySelector('input[type="file"]').addEventListener('change', function(e) {
var blob = this.files[0];
const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
const SIZE = blob.size;
var start = 0;
var end = BYTES_PER_CHUNK;
while(start < SIZE) {
upload(blob.slice(start, end));
start = end;
end = start + BYTES_PER_CHUNK;
}
}, false);