js Blob 与 ArrayBuffer
一、Blob
概念:
Blob(Binary Large Object)表示二进制类型的大对象,通常是影像、音频、文本等多媒体文件;在 javascript 中,Blob 类型的对象是不可改变的原始数据
语法:
new Blob(blobParts, option)
示例:
- 通过字符串创建一个 Blob
1 const helloWorld = new Blob(["hello", " world"], { 2 type: "text/plain", 3 endings: "transparent", 4 }); 5 console.log(helloWorld); // Blob {size: 11, type: 'text/plain'}
- 通过 Blob 创建一个新的 Blob
1 const helloVue = new Blob([helloWorld.slice(0, 5), " vue"], { 2 type: "text/plain", 3 endings: "transparent", 4 }); 5 console.log(helloVue); // Blob {size: 9, type: 'text/plain'}
- 分片上传
1 function handle(blob, chunkSize, upload) { 2 const size = blob.size; 3 let start = 0, 4 end = chunkSize; 5 while (start < size) { 6 upload(blob.slice(start, end, "text/plain")); 7 start = end; 8 end = start + chunkSize; 9 } 10 } 11 // 每次上传 4 个字节哈哈 12 handle(helloVue, 4, (chunk) => console.log(chunk));
二、Blob URL
概念:
Blob URL 是一种伪协议,浏览器内部为每个 Blob URL 存储了一个 URL → Blob 的映射,如果这个映射不存在了,则会从浏览器中收到 404 错误;因此,此类 URL 较短,生成的 URL 仅在当前文档下才有效
特性:
由于有映射关系的存在,Blob 无法释放;可以手动销毁映射,或关闭当前文档
示例:
1 const link = URL.createObjectURL(helloVue); 2 const _link = URL.createObjectURL(helloVue); 3 console.log(link); // blob:null/fffb6ef0-9a06-4503-b982-058929da566b 4 console.log(_link); // blob:null/cdbb625f-c99a-4d4e-bd10-70136f0d270a /* Blob URL 是随机的 */ 5 6 /* 可以作为 a 标签的 link;如果是图片,也可以作为 img 的 src */ 7 8 // 销毁 Blob URL;否则 Blob 得不到释放,会产生内存泄漏 9 URL.revokeObjectURL(link); 10 URL.revokeObjectURL(_link);
三、File
概念:
继承自 Blob
语法:
new File(blobParts, name, option)
示例:
1 // 创造一个 .txt 文件 2 const file = new File([helloVue], "test.txt", { 3 type: "text/plain", 4 });
四、FileReader
作用:
用来读取 Blob,并转换为其他类型的数据
转换方式:
readAsArrayBuffer、readAsBinaryString、readAsDataURL、readAsText
示例:
1 const reader = new FileReader(); 2 3 reader.onload = function (e) { 4 console.log(this.result); // hello vue 5 }; 6 reader.readAsText(file);
五、ArrayBuffer
概念:
表示通用的、固定长度的原始二进制缓冲区
与数组的区别:
数组存在在堆中,ArrayBuffer 存放在栈中
与 Blob 的区别:
Blob 不可被修改,只能重新创建新的 Blob;ArrayBuffer 可以视图化,然后修改
TypeArray 类型具体包含以下方法:
Int8Array、Uint8Array、Uint8ClampedArray(颜色专用)、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array、Float64Array
DataView 类包含以下方法:
getInt8、setInt8、getUint8、setUint8 等;没有与 Uint8ClampedArray 相关对应的方法
示例:
- 创建一个长度为 4 个字节的 ArrayBuffer
1 const buffer = new ArrayBuffer(4); 2 console.log(buffer); // ArrayBuffer(4)
- 创建一个 Int8 视图
1 const view0 = new Int8Array(buffer); 2 console.log(view0); // Int8Array(4) [0, 0, 0, 0]
- 填充为“food”字符串
1 "food".split("").forEach(function (char, index) { 2 view0[index] = char.charCodeAt(0); 3 }); 4 console.log(view0); // Int8Array(4) [102, 111, 111, 100]
- 转为字符串
1 const food = String.fromCharCode.apply(null, view0); 2 console.log(food); // food
- 转为数组
1 const foodUnicode = Array.from(view0); 2 console.log(foodUnicode); // [102, 111, 111, 100]
- 也可以直接创建一个已填充的视图
1 const view1 = new Int8Array(foodUnicode); 2 console.log(view1); // Int8Array(3) [102, 111, 111, 100]
- 复制一段缓冲区
1 // 类型化数组的 set 方法用于复制一段内存;它是整段内存的复制,比一个个拷贝成员的那种复制快得多 2 const view2 = new Int8Array(8); 3 view2.set(view0); 4 console.log(view2); // Int8Array(8) [102, 111, 111, 100, 0, 0, 0, 0]
- 也可以截取一段缓冲区
1 const fooBuffer = view1.buffer.slice(0, 3); 2 const fooView = new Int8Array(fooBuffer); 3 console.log(fooView); // Int8Array(3) [102, 111, 111]
- 转为 Blob
1 const foo = new Blob([fooBuffer], { 2 type: "text/plain", 3 endings: "transparent", 4 }); 5 console.log(foo); // Blob {size: 3, type: 'text/plain'}
六、Data URL
格式:
data:[MIME type];encoding,content
七、实战
通过文件二进制头判断文件类型
1 <input type="file" onchange="handle(event)" />; 2 <script> 3 function getFileType(file) { 4 return new Promise((resolve, reject) => { 5 if (!file) return; 6 const types = ["PNG", "GIF"]; 7 let fileType = ""; 8 file.arrayBuffer().then((buffer) => { 9 const view = new Uint8Array(buffer.slice(0, 8)); 10 const fileHead = String.fromCharCode.apply(null, view); 11 types.forEach(function (type) { 12 if (fileHead.includes(type)) { 13 fileType = type; 14 } 15 }); 16 resolve(fileType); 17 }); 18 }); 19 } 20 function handle(e) { 21 const file = e.target.files[0]; 22 getFileType(file).then((res) => { 23 console.log(res); 24 }); 25 } 26 </script>