Base64
基于64个可打印字符来表示二进制数据的表示方法
二进制数据,每个字符取值范围[0, 255]
,作为ascii码解析时,只有部分可显示(打印)
肉眼查看/作为文本拷贝这份数据,16进制优于二进制ascii码格式
但16进制表示法需两个字节才能表示表示原始数据的一个字节,即大小增加了一倍
base64算法保持编码后可打印特性的同时,大小只增加 1/3
算法原理
log₂64 = 6
每6个比特为一个单元,对应某个可打印字符。3个字节=24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示
解码时将每个可打印的字符按映射表对应,每4个字节看成一个单位,按位运算还原出原始3个字节
原始数据长度不是3的倍数?
一种是最后剩1个字节,另一种是剩两个字节:
- 剩余1个字节时,1个字节编码成2个字节,剩余2个字节填充为 ==
- 剩余2个字节时,2个字节编码成3个字节,剩余1个字节填充为 =
即base64保证了编码后的字符串长度为4的倍数
URL-safe variant
标准 Base64 编码字符集中包含 +
, /
, =
,在 URL 中使用时需要特别处理。为避免对 URL 造成干扰,RFC 4648 的 Base64 URL-safe variant 提出了将:
+
替换为-
/
替换为_
=
(填充符)通常省略
Java 示例:使用 java.util.Base64
import java.util.Base64;
public class Base64UrlExample {
public static void main(String[] args) {
String original = "hello/world?key=1+2=";
// 编码
String encoded = Base64.getUrlEncoder().withoutPadding().encodeToString(original.getBytes());
System.out.println("URL-safe Base64 Encoded: " + encoded);
// 解码
byte[] decodedBytes = Base64.getUrlDecoder().decode(encoded);
String decoded = new String(decodedBytes);
System.out.println("Decoded: " + decoded);
}
}
输出示例:
vbnet复制编辑URL-safe Base64 Encoded: aGVsbG8vd29ybGQ_a2V5PTErMj0
Decoded: hello/world?key=1+2=
Go 示例:使用 encoding/base64
package main
import (
"encoding/base64"
"fmt"
)
func main() {
original := "hello/world?key=1+2="
// 编码
encoded := base64.RawURLEncoding.EncodeToString([]byte(original))
fmt.Println("URL-safe Base64 Encoded:", encoded)
// 解码
decodedBytes, err := base64.RawURLEncoding.DecodeString(encoded)
if err != nil {
panic(err)
}
fmt.Println("Decoded:", string(decodedBytes))
}
输出示例:
vbnet复制编辑URL-safe Base64 Encoded: aGVsbG8vd29ybGQ_a2V5PTErMj0
Decoded: hello/world?key=1+2=
Base58
Bitcoin中使用的一种独特的编码方式,主要用于产生Bitcoin的钱包地址。相比Base64,Base58不使用数字"0",字母大写"O",字母大写"I",和字母小写"l",以及"+“和”/“符号
设计Base58主要的目的是:
-
避免混淆。在某些字体下,数字0和字母大写O,以及字母大写I和字母小写l会非常相似
-
不使用 + 和 / 的原因是非字母或数字的字符串作为帐号较难被接受
-
没有标点符号,通常不会被从中间分行
-
大部分的软件支持双击选择整个字符串