您好,登錄后才能下訂單哦!
這篇文章主要介紹“如何實現Base64與Base32”,在日常操作中,相信很多人在如何實現Base64與Base32問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何實現Base64與Base32”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
要寫Base32,就要先理解Base64,那么Base64是干什么用的呢?為什么要有Base64呢?這個是根本原因,把Base64產生的過程搞清楚了,那么Base32,我們就可以依葫蘆畫瓢了。
我們知道在計算機中,數據的單位是字節byte,它是由8位2進制組成的,總共可以有256個不同的數。那么這些二進制的數據要怎么進行傳輸呢?我們要將其轉化為ASCII字符,ASCII字符中包含了33個控制字符(不可見)和95個可見字符,我們如果能將這些二進制的數據轉化成這95個可見字符,就可以正常傳輸了。于是,我們從95個字符中,挑選了64個,將2進制的數據轉化為這個64個可見字符,這樣就可以正常的傳輸了,這就是Base64的由來。那這64個字符是什么呢?
這就是Base64的那64個字符。那么如果我們要實現Base32呢?對了,我們要挑選出32個可見字符,具體如下:
private static final char[] toBase32 = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5' };
我們挑選了大寫的A-Z,再加上0-5,一共32個可見字符。
好了,32個可見字符已經選好了,接下來就是將2進制轉化成這32個字符的過程。我們先來看一下Base64是一個什么樣的轉化過程,我們一個字節是8位,而64是2的6次方,也即是一個字節(8位)的數據,我們要截取其中的6位進行編碼,取到其可見字符。那么剩余的2位數怎么辦呢?它將和下一個自己的前4位組成一個6位的數據進行編碼。那么我們需要多少字節才能得到一個完整的不丟位的編碼呢?我們要取6和8的最小公倍數,也就是24,24位恰好是3個字節,如果取6位進行編碼,則可以取到4個編碼。我們看看下面的圖就可以更好地理解了,
M,a,n對應的ASCII碼分別是77,97,110。
對應的二進制是01001101,01100001,01101110。
然后我們按照6位截取,恰好能夠截取4個編碼,對應的6位二進制分別為:010011,010110,000101,101110。
對應的64位編碼為:T,W,F,u。
同理,如果我們要實現Base32怎么辦呢?32是2的5次方,那么我們再進行2進制截位時,要一次截取5位。那么一個字節8位,截取了5位,剩下的3位怎么辦?同理和下一個字節的前2位組成一個新的5位。那么多少個字節按照5位截取才能不丟位呢?我們要取5和8的最小公倍數,40位,按照5位截取,正好得到8個編碼。40位,正好5個字節,所以我們要5個字節分為一組,進行Base32的編碼。如下圖:
對比前面的Base64,Base32就是按照5位去截取,然后去編碼表中找到對應的字符。好了,原理我們明白了,下面進入程序階段。
原理明白了,程序怎么寫呢?這也就是程序猿的價值所在,把現實中的規則、功能、邏輯用程序把它實現。但是實現Base32也是比較難的,不過有先人給我們留下了Base64,我們參照Base64去實現Base32就容易多了。
首先,我們要根據輸入字節的長度,確定返回字節的長度,以上面為例,輸入字節的長度是5,那么Base32轉碼后的字節長度就是8。那么如果輸入字節的長度是1,返回結果的字節長度是多少呢?這就需要補位了,也就是說輸入字節的長度不是5的倍數,我們要進行補位,將其長度補成5的倍數,這樣編碼以后,返回字節的長度就是8的倍數。這樣做,我們不會丟失信息,比如,我們只輸入了一個字節,是8位,編碼時,截取了前5位,那么剩下的后3位怎么辦?不能舍棄吧,我們要在其后面補足40位,補位用0去補,前面截取有剩余的位數再加上后面補位的0,湊成5位,再去編碼。其余的,全是0的5位二進制,我們編碼成“=”,這個和Base64是一樣的。
好了,我們先來看看編碼后返回字節的長度怎么計算。
//返回結果的數組長度 int rLength = 8 * ((src.length + 4) / 5); //返回結果 byte[] result = new byte[rLength];
其中src是輸入的字節數組;
返回長度的公式我們要仔細看一下,對5取整,再乘以8,這是一個最基本的操作,我們用上面的例子套一下,輸入字節的長度是5個字節,8*(5/5) = 8,需要返回8個字節。我們再來看看加4的作用,比如我們輸入的是1個字節,那么返回幾個字節呢?按照前面的要求,如果二進制長度不滿40位,要補滿40位,也就是輸入字節的長度要補滿成5的整數倍。這里先加4再對5取整,就可以補位后可以進行完整編碼的個數,然后再乘以8,得到返回的字節數。大家可以隨便想幾個例子,驗證一下結果對不對。
然后我們定義返回結果的數組。
返回結果的數組長度已經確定了,接下來我們做什么呢?當然是編碼的工作了,這里我們分為兩個步驟:
先處理可以正常進行編碼的那些字節,也就是滿足5的倍數的那些字節,這些字節可以進行5字節到8字節轉換的,不需要進行補位。
然后處理最后幾位,這些是需要補位的,將其補成5個字節。
編碼的步驟已經確定了,下面要確定可以正常編碼的字節長度,以及需要補位的長度,如下:
//正常轉換的長度 int normalLength = src.length / 5 * 5; //補位長度 int fillLength = (5 - (src.length % 5)) % 5;
又是兩個計算公式,我們分別看一下:
可以正常編碼的字節長度,對5取整,再乘以5,過濾掉最后不滿足5的倍數的字節,這些過濾掉的字節需要補位,滿足5個字節;
這一步就是計算最后需要補幾位才能滿足5的倍數,最后可以得到需要補位的長度,如果輸入字節的長度恰好是5的倍數,不需要補位,則計算的結果是0,大家可以驗證一下這兩個公式。
接下來,我們處理一下可以正常編碼的字節,如下:
//輸入字節下標 int srcPos = 0; //返回結果下標 int resultPos = 0; while (srcPos < normalLength) { long bits = ((long)(src[srcPos++] & 0xff)) << 32 | (src[srcPos++] & 0xff) << 24 | (src[srcPos++] & 0xff) << 16 | (src[srcPos++] & 0xff) << 8 | (src[srcPos++] & 0xff); result[resultPos++] = (byte) toBase32[(int)((bits >> 35) & 0x1f)]; result[resultPos++] = (byte) toBase32[(int)((bits >> 30) & 0x1f)]; result[resultPos++] = (byte) toBase32[(int)((bits >> 25) & 0x1f)]; result[resultPos++] = (byte) toBase32[(int)((bits >> 20) & 0x1f)]; result[resultPos++] = (byte) toBase32[(int)((bits >> 15) & 0x1f)]; result[resultPos++] = (byte) toBase32[(int)((bits >> 10) & 0x1f)]; result[resultPos++] = (byte) toBase32[(int)((bits >> 5) & 0x1f)]; result[resultPos++] = (byte) toBase32[(int)(bits & 0x1f)]; }
我們先定義輸入字節的下標和返回結果的下標,用作取值與賦值;
再寫個while循環,只要輸入的字節下標在正常轉換的范圍內,就可以正常的編碼;
接下來看看while循環的處理細節,我們先要將5個字節拼成一個40位的二進制,在程序中,我們通過位移運算和 |
或運算得到一個long型的數字,當然它的二進制就是我們用5個字節拼成的。
這里有個坑要和大家說明一下,我們第一個字節位移的時候用long轉型了,為什么?因為int型在Java中占4個字節,32位,我們左移32位后,它會回到最右側的位置。而long占64位,我們左移32位是不會循環的。這一點大家要格外注意。
接下來就是將這40位的二進制進行分拆,同樣通過位移操作,每次從左側截取5位,我們分別向右移動35、30、25、20、15、10、5、0,然后將其和0x1f
進行與操作,0x1f
是一個16進制的數,其二進制是0001 1111,對了,就是5個1,移位后和0x1f
進行與操作,只留取最右側的5位二進制,并計算其數值,然后從32位編碼表中找到對應的字符。
可以正常編碼的部分就正常結束了,大家要多多理解位移符號的運用。接下來,我們再看看結尾字節的處理。先上代碼:
if (fillLength > 0) { switch (fillLength) { case 1: int normalBits1 = (src[srcPos] & 0xff) << 24 | (src[srcPos+1] & 0xff) << 16 | (src[srcPos+2] & 0xff) << 8 | (src[srcPos+3] & 0xff); result[resultPos++] = (byte) toBase32[(normalBits1 >> 27) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits1 >> 22) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits1 >> 17) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits1 >> 12) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits1 >> 7) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits1 >> 2) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits1 << 3) & 0x1f]; result[resultPos++] = '='; break; case 2: int normalBits2 = (src[srcPos] & 0xff) << 16 | (src[srcPos+1] & 0xff) << 8 | (src[srcPos+2] & 0xff); result[resultPos++] = (byte) toBase32[(normalBits2 >> 19) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits2 >> 14) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits2 >> 9) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits2 >> 4) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits2 << 1) & 0x1f]; result[resultPos++] = '='; result[resultPos++] = '='; result[resultPos++] = '='; break; case 3: int normalBits3 = (src[srcPos] & 0xff) << 8 | (src[srcPos+1] & 0xff); result[resultPos++] = (byte) toBase32[(normalBits3 >> 11) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits3 >> 6) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits3 >> 1) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits3 << 4) & 0x1f]; result[resultPos++] = '='; result[resultPos++] = '='; result[resultPos++] = '='; result[resultPos++] = '='; break; case 4: int normalBits4 = (src[srcPos] & 0xff) ; result[resultPos++] = (byte) toBase32[(normalBits4 >> 3) & 0x1f]; result[resultPos++] = (byte) toBase32[(normalBits4 << 2) & 0x1f]; result[resultPos++] = '='; result[resultPos++] = '='; result[resultPos++] = '='; result[resultPos++] = '='; result[resultPos++] = '='; result[resultPos++] = '='; break; } }
fillLength
就是需要補位的位數,如果等于0,我們就不需要補位了。大于0就需要進行補位。
需要補位的情況,我們分為4種,分別為:補1位、補2位、補3位和補4位。
我嗯先看看補1位的情況,需要補1位,說明之前剩下4個字節,我們先將這4個字節拼起來,那么第一個字節要向左移動24位,這個和正常情況下第一個字節向左移動的位數是不一樣的。剩余的字節分別向左移動相應的位數,大家可以參照程序計算一下。
然后將得到的32位二進制數,從最高位每次截取5位,每次向右移動位數分別為27、22、17、12、7、2,注意,最后剩下2位,不足5位,我們要向左移動3位。移位后要和0x1f
進行與操作,這個作用和前面是一樣的,這里不贅述了。然后將得到的數字在32位編碼表中,去除對應的字符。
剩下的位數我們統一使用=
進行補位。
其他的需要補1位、補2位和補3位的情況,我們重復步驟3-步驟5,里邊具體的移動位數有所區別,需要大家仔細計算。
整個的編碼過程到這里就結束了,我們將result數組返回即可。
到此,關于“如何實現Base64與Base32”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。