之前也遇到过base64的encoding,当时并不清楚为什么需要base64编码。今天花时间了解了一下。这个文章写的挺详细的:Base64编码原理与应用。所以我也不需要复述过多的东西。
简单总结:因为单纯的2进制是使用ascii码的,所以会存在部分字符不可见,在不可见的情况下,你存在文件,实实在在写进去,没有问题,但是在一些场景,就是需要将他们表示成可见字符,比如url,不然有的处理会把一些字符理解成控制的特殊标记从而造成错误。或者JSOM,XML里面就是不支持binary,所以就是需要base64的存在了。
那这个base64把3个byte就是24个bit,转成4个base64字符,每个代表6个bit。但是这四个字符是实实在在存成ascii的(可见),所以消耗存储长度是32bit。所以说base64编码多消耗了33%的存储空间。
看看go里面base64的编码。里面的NoPadding就是那个文章里说的要不要加=号。解码也是相似的位运算,但是因为需要考虑有没有padding,就需要有一些判断,但是思想一样。下面代码是编码过程,加了一些注释。
func TestBase64() {
str := "hello"
encoded := base64.StdEncoding.EncodeToString([]byte(str))
fmt.Println(encoded)
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
fmt.Println("decode error:", err)
return
}
fmt.Println(string(decoded))
}
output:
aGVsbG8=
hello
func (enc *Encoding) EncodeToString(src []byte) string {
buf := make([]byte, enc.EncodedLen(len(src)))
enc.Encode(buf, src)
return string(buf)
}
func (enc *Encoding) EncodedLen(n int) int {
if enc.padChar == NoPadding {
return (n*8 + 5) / 6 // minimum # chars at 6 bits per char
}
// 这个就是除三取上整,然后乘4,相当于把3个变成4个字符。所以就是3个一组的转换
return (n + 2) / 3 * 4 // minimum # 4-char quanta, 3 bytes each
}
unc (enc *Encoding) Encode(dst, src []byte) {
if len(src) == 0 {
return
}
di, si := 0, 0
n := (len(src) / 3) * 3
for si < n {
// Convert 3x 8bit source bytes into 4 bytes
// 全部都是位运算,也很简单,用src字符串中的3个取或运算
val := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2])
// 把24位分给四个,那个0x3F就是6个1,与运算就取出来最低6位。
dst[di+0] = enc.encode[val>>18&0x3F]
dst[di+1] = enc.encode[val>>12&0x3F]
dst[di+2] = enc.encode[val>>6&0x3F]
dst[di+3] = enc.encode[val&0x3F]
si += 3
di += 4
}
remain := len(src) - si
if remain == 0 {
return
}
// Add the remaining small block
//src字符串不够3整除的时候,结尾只能剩1或者2个,根据情况来追加即可。
val := uint(src[si+0]) << 16
if remain == 2 {
val |= uint(src[si+1]) << 8
}
dst[di+0] = enc.encode[val>>18&0x3F]
dst[di+1] = enc.encode[val>>12&0x3F]
//补等号
switch remain {
case 2:
dst[di+2] = enc.encode[val>>6&0x3F]
if enc.padChar != NoPadding {
dst[di+3] = byte(enc.padChar)
}
case 1:
if enc.padChar != NoPadding {
dst[di+2] = byte(enc.padChar)
dst[di+3] = byte(enc.padChar)
}
}
}











网友评论