一直以来,前端的工做主要涉及的是字符串操做,而对二进制的数据接触较少。可是这种需求却一直存在着,尤为是HTML5以后,随着web应用愈来愈复杂,File,Blob,TypedArray这些API的出现使得前端对二进制的操做更加方便。
html
这两个函数的应用场景之一是解密大佬留下的微信号😂,函数名中的a,b分别表明 ASCII 和 binary string。谈到这两个函数就不得不提到base64。Base64就是一种基于64个可打印字符来表示二进制数据的方法.Base64 encode获得的字符串是ASCII码的子集。那么什么又是binary string呢? binary string设计的目的是用来表明和操做二进制数据,而不是用来编码字符串的。前端
为何中文不能使用atob,btoa函数?由于binary string的范围是0-255,中文utf-8已经超过这个范围了。这篇文章讲解了字符编码(ASCII LATIN1 UTF8)相关知识。web
参考: 廖雪峰json
以对'A'base64编码为例:canvas
btoa('A') //"QQ=="
根据base64的原理,咱们试着本身实现一下:后端
//1. charcode 'A'.charCodeAt().toString(2) //"1000001" //7位前面补成8位 加一个0 "1000001".padStart(8, '0') //"01000001" //3. 为了达到24位的整数倍,补两个0x00 "01000001" + '00'.repeat(8) //"010000010000000000000000" //4. 按6位一组分开 ["010000", "010000", "000000", "000000"]=> [16,16,0,0] => [Q,Q,A,A] //查表获得字符串,两个==表示补了两字节0x00,也取代了原来的A的做用,补了0x00以后,生成的base64字符串末尾确定是0 `QQ==`
综上所述,通过base64编码获得的字符串长度必定是4的倍数。末尾可能有0,1,2个等号,用来表示在编码时补位的个数。api
'😂'.length // 2 '😂'.charCodeAt().toString(16) //"d83d" '😂'.charCodeAt(1).toString(16) //"de02" "\ud83d\ude02" //"😂"
首先咱们要知道utf-8的补位,接下来会分如下几步浏览器
'中'.charCodeAt(0) // 20013 (20013).toString(2) // 获得"100111000101101" 15位, //1 先高位补一个0凑成16位"0100111000101101", //2 再按UTF-8编码规则,1110 {4} 10 {6} 10 {6}获得24位 111001001011100010101101 //3 再拆分红8位一组。[11100100,10111000,10101101] //4 再2进制转换成16进制["e4", "b8", "ad"] //5 最后toUpperCase,%链接
在浏览器中,咱们能够经过File api操做文件,咱们能够经过input元素拿到file,也能够直接调用构造函数建立一个file实例微信
// 从input元素中读取一个文件: let fileInput = document.getElementById('file') fileInput.onchange = console.log(fileInput.files[0]) // 直接建立一个 let file = new File(['1'], '1.txt') file instanceof File // true file instanceof Blob // true
file和其余类型之间的转换是一个异步的过程,是经过fileReader来实现的,转换的结果在reader的onload事件中获取,代码以下:异步
dataUrl除去MIME信息之外才是base64的数据
let reader = new FileReader(); reader.onload = event => console.log(event.target.result); reader.readAsDataURL(file);
let reader = new FileReader(file); reader.onload = event => console.log(event.target.result) reader.readAsArrayBuffer(file);
reader.readAsBinaryString(file)
function dataURLtoFile(dataurl, filename) { let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, {type:mime}); }
媒体类型(一般称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。
全部的MIME类型能够在这里找到:https://www.iana.org/assignments/media-types/media-types.xhtml
再提一下文件编码格式,参考文章,使用hexdump
命令能够查看文件的二进制编码。
// 异步,blob会被传到callback的参数中 canvas.toBlob(callback, mimeType, qualityArgument); //同步 canvas.toDataURL(type, encoderOptions);
objectURL = URL.createObjectURL(blob); //"blob:https://i.cnblogs.com/64556585-a84a-450c-b7a3-bd54a51b5fdd"
爱奇艺的视频地址使用这种方式
blob和arraybuffer的区别能够看这里
将blob转成arrayBuffer: blob => FileReader.readAsArrayBuffer => arrayBuffer
直接建立个arrayBuffer
new ArrayBuffer(length)
typedArray不是一个api,而是一类api的统称,它们被设计用来操做arrayBuffer,可是不能直接接收blob,构造函数以下:
new TypedArray(length); new TypedArray(typedArray); new TypedArray(object); new TypedArray(buffer [, byteOffset [, length]]);
typedArray是操做arrayBuffer的方式
元素的容量不一样,详见:MDN
好比:Int8Array元素大小1字节,Int16Array每一个元素占2字节
xhr2, fetch,Response,Request,Body
res.json() res.text() res.arrayBuffer()
当后端以流的形式返回一个图片时:
fetch(imgurl).then(res => { return res.blob() }).then(blob => { if (blob) { // 以objectUrl形式显示 img.src = URL.createObjectURL(blob); // 以dataUrl形式显示图片 let reader = new FileReader(blob); reader.onload = event => { img.src = event.target.result; } reader.readAsDataURL(blob); }
直接传递便可
参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Typed_arrays