本文主要是介绍Go语言base64流式编码在收尾时的一个小坑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
问题复现
请看下面代码
sb := strings.Builder{}
_, err := io.Copy(base64.NewEncoder(base64.StdEncoding, &sb),bytes.NewBufferString("12345678"),
)
if err != nil {panic(err)
}
fmt.Println("编码后:", sb.String())
data, err := base64.StdEncoding.DecodeString(sb.String())
if err != nil {panic(err)
}
fmt.Println("解码后:", string(data))
这里利用io.Copy
将任意io.Reader
编码为base64字符串,这种写法在处理网络通信等流式数据时十分简洁高效。可是,以上代码运行结果如下:
编码后: MTIzNDU2
解码后: 123456
显见,末尾的78
被丢掉了。
原因分析
base64结尾处使用=
或==
标记编码未满,因此流式编码器在不知道当前是否为文件末尾时,不会贸然写入=
或==
,而是统一以3字节组进行编码,将不满3字节的写入数据残余部分先暂存起来。
这样做是因为每3字节原始数据正好对应4字节base64编码,而完整的base64编码并不包含=
与==
,因此可以直接写入接收端。
为了适配流式编码,base64.NewEncoder
返回的并不是io.Writer
而是io.WriteCloser
。我们必须要显式调用其Close
方法以通知编码器写入结尾残余部分,否则当原始数据长度不是3的倍数时,将在结尾处出现结尾缺损。
解决方案
编码结束后调用流式编码器的Close
方法。
sb := strings.Builder{}
enc := base64.NewEncoder(base64.StdEncoding, &sb)
_, err := io.Copy(enc,bytes.NewBufferString("12345678"),
)
if err != nil {panic(err)
}
err = enc.Close()
if err != nil {panic(err)
}
fmt.Println("编码后:", sb.String())
data, err := base64.StdEncoding.DecodeString(sb.String())
if err != nil {panic(err)
}
fmt.Println("解码后:", string(data))
此时,输出恢复正常。
编码后: MTIzNDU2Nzg=
解码后: 12345678
这篇关于Go语言base64流式编码在收尾时的一个小坑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!