一直以來,前端的工做主要涉及的是字符串操做,而對二進制的數據接觸較少。可是這種需求卻一直存在着,尤爲是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