首页 > 其他分享 >Base64编码

Base64编码

时间:2024-06-22 09:55:27浏览次数:27  
标签:编码 字符 Base64 索引 println byte

URL 编码是对字符进行编码,表示成 %xx ​的形式,而 Base64 编码是对二进制数据进行编码,表示成文本格式。

为什么需要 Base64 编码

Base64 编码的目的是把二进制数据变成文本格式,这样在很多文本中就可以处理二进制数据。例如,电子邮件协议就是文本协议,如果要在电子邮件中添加一个二进制文件(比如图片),就可以用 Base64 编码,然后以文本的形式传送。

而且有时候一些路由器等硬件也不兼容二进制,或者一些网络协议不兼容,因此得转为字符形式。

还有的时候,使用文本形式能减少一次 http 请求,提高效率:打开 google 的首页,就能看到某些样式中的图片不是一个资源地址,而是 base64 编码的字符串。通过 base64 来传输图片,然后浏览器解码该 base64,就能得到图片了。

注意:并不是什么图片都适合用 base64 来处理,因为图片越大,转换的 base64 的字符串就越长,对带宽的要求更高了。

​​

Base64 编码转换规则

Base64 编码可以把任意长度的二进制数据变为纯文本,且只包含 A​ ~Z​,a​ ~z​,0​ ~9​、+​、/​、= ​这些字符。它的原理是把 3 字节的二进制数据按 6bit 一组,用 4 个 int 整数表示,然后把这个整数作为索引查表,得到对应的字符,最终得到编码后的字符串。

  • 6 位整数的范围总是 0​ ~63​,所以,能用 64 个字符表示:
  • 字符 A​ ~Z​对应索引 0​ ~25​,
  • 字符 a​ ~z​对应索引 26​ ~51​,
  • 字符 0​ ~9​对应索引 52​ ~61​,
  • 最后两个索引 62​、63​分别用字符 +​和 /​表示。

索引表如下(摘自 RFC2045):

Table 1: The Base64 Alphabet

索引 对应字符 索引 对应字符 索引 对应字符 索引 对应字符
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v

14 O 31 f 48 w

15 P 32 g 49 x

16 Q 33 h 50 y

举个例子:3 个 byte 数据分别是 e4、b8、ad,按 6bit 分组得到 39、0b、22 和 2d(十六进制下):

┌───────────────┬───────────────┬───────────────┐
│      e4       │      b8       │      ad       │
└───────────────┴───────────────┴───────────────┘
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│1│1│1│0│0│1│0│0│1│0│1│1│1│0│0│0│1│0│1│0│1│1│0│1│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
┌───────────┬───────────┬───────────┬───────────┐
│    39     │    0b     │    22     │    2d     │
└───────────┴───────────┴───────────┴───────────┘

根据查表可得最后的字符是 5Lit​ 这四个字符。

需要注意的是,根据 ASCII 编码,4 个字符占了 4*8=32 个 bit,比起原始的 bit 位数多了 1/3,传输效率会降低。字符越少,编码的效率就会越低。

如果把 Base64 的 64 个字符编码表换成 32 个、48 个或者 58 个,就可以使用 Base32 编码,Base48 编码和 Base58 编码。

Java 中的 Base64 编码

Java 提供了不少类来对二进制数据进行 Base64 编码和解码。

例如对上述例子进行编码:

import java.util.Base64;

public class TestBase64{
  public static void main(String[] args) {
    byte[] input = new byte[]{ (byte)0xe4, (byte)0xb8, (byte)0xad};
    String base64Encoded = Base64.getEncoder().encodeToString(input);
    System.out.println(base64Encoded);  //5Lit
  }
}

解码:以补码形式输出结果

    byte[] output = Base64.getDecoder().decode("5Lit");
    System.out.println(Arrays.toString(output));  //[-28, -72, -83]

如果不是 3 的倍数...

如果输入的 byte[] ​数组长度不是 3 的整数倍肿么办?这种情况下,需要对输入的末尾补一个或两个 0x00​,编码后,在结尾加一个 = ​表示补充了 1 个 0x00​,加两个 = ​表示补充了 2 个 0x00​,解码的时候,去掉末尾补充的一个或两个 0x00 ​即可。

实际上,因为编码后的长度加上 = ​总是 4 的倍数,所以即使不加 = ​也可以计算出原始输入的 byte[]​。Base64 编码的时候可以用 withoutPadding() ​去掉 =​,解码出来的结果是一样的:

import java.util.Arrays;
import java.util.Base64;

public class TestBase642 {
    public static void main(String[] args) {
        byte[] input = new byte[] { (byte) 0xe4, (byte) 0xb8, (byte) 0xad, 0x21 };
        String b64encoded = Base64.getEncoder().encodeToString(input);
        String b64encoded2 = Base64.getEncoder().withoutPadding().encodeToString(input);
        System.out.println(b64encoded);
        System.out.println(b64encoded2);
        byte[] output = Base64.getDecoder().decode(b64encoded2);
        System.out.println(Arrays.toString(output));
    }
}

运行结果:

5LitIQ==
5LitIQ
[-28, -72, -83, 33]

因为标准的 Base64 编码会出现 +​、/ ​和 =​,所以不适合把 Base64 编码后的字符串放到 URL 中。一种针对 URL 的 Base64 编码可以在 URL 中使用的 Base64 编码,它仅仅是把 + ​变成 -​,/ ​变成 _​:

import java.util.Arrays;
import java.util.Base64;

public class TestBase643 {
    public static void main(String[] args) {
        byte[] input = new byte[] { 0x01, 0x02, 0x7f, 0x00 };
        String b64encoded = Base64.getUrlEncoder().encodeToString(input);
        System.out.println(b64encoded);
        byte[] output = Base64.getUrlDecoder().decode(b64encoded);
        System.out.println(Arrays.toString(output));
    }
}

运行结果:

AQJ_AA==
[1, 2, 127, 0]

参考

编码算法 - 廖雪峰的官方网站

为什么要使用 base64 编码,有哪些情景需求? - 知乎

Base64 编码原理与应用

标签:编码,字符,Base64,索引,println,byte
From: https://www.cnblogs.com/PeterJXL/p/18261882

相关文章

  • 基于机会网络编码(COPE)的卫星网络路由算法matlab仿真
    1.程序功能描述       基于机会网络编码(COPE)的卫星网络路由算法。基于机会的网络编码(COPE,completelyopportunityencoding)方法,使每个接收节点都对信道进行侦听,通过获取邻居节点的信息状态确定编码机会,并且在本地信息缓存区中进行编码,最后进行基于编码机会的路由,可以有......
  • 信道编码——Turbo码Matlab编译码实现与性能分析
    第三篇博客感言“不要成为一个只会用Matlab仿真SNR-BER的猴子。”前段时间比较焦虑就业,到处搜索通信的就业情况。很多人说通信日薄西山,不无道理,与前十几二十年相比,现在的确是哑火了,5G、6G带来的变革远不如3G、4G那么震撼,并且电子信息专业学生越来越多,就业岗位和待遇却不见......
  • 搜索硬编码中文
    老项目中常常有直接在代码里或者xml布局中硬编码中文的,在后期业务扩展做国际化翻译时,这就是一个巨大的坑,因为我们需要知道哪里硬编码了,然后提取到strings.xml中刚好我最近在弄这个,如何找到代码中所有的硬编码就是核心问题,下面记录下我的步骤 1.首先写好正则,直接百度也行^((?!......
  • URL编码
    URL编码是浏览器发送数据给服务器时使用的编码,它通常附加在URL的参数部分。‍为什么需要URL编码举个例子,我们在百度里搜索“中文”这两个字,其发送给后台服务器的网址类似这样的:https://www.baidu.com/s?wd=%E4%B8%AD%E6%96%87我们可以打开浏览器控制台查看:​这些字符串......
  • 基于哔哩哔哩视频库的音频提取播放器,实现下载B站音频到本地,方便把鬼畜下载到手机上,项
    importreimportjsonimportthreadingimporttimeimportosimportshutilimportsubprocessimportrequestsimportPySimpleGUIassgos.environ['PYGAME_HIDE_SUPPORT_PROMPT']="hide"frompygameimportmixersg.theme('SystemDef......
  • 理解视频编码中的 I 帧和 IDR 帧
    视频编码是将视频数据进行压缩和解压缩的过程,以减少存储和传输带宽需求。在这个过程中,不同类型的帧(帧是视频的基本组成单元)扮演着不同的角色。I帧(Intra-codedFrame)I帧是视频编码中的一种关键帧,它独立于其他帧进行编码。这意味着一个I帧可以完全重建出一个完整的图像,而不......
  • 编程语言与字符编码
    聊聊在编程语言中的字符,例如Java‍一个字符占多少个字节?得看情况,不同编码下情况不同。这里引用肖国栋大佬的知乎回答:具体地讲,脱离具体的编码谈某个字符占几个字节是没有意义的。就好比有一个抽象的整数“42”,你说它占几个字节?这得具体看你是用byte,short,int,还是long来......
  • 编码在网络安全中的应用和原理
    什么是编码,为什么要有编码?众所周知,计算机只能够理解0和1,也就是二进制。可是我们的世界0和1以外,还有太多太多的符号和语言了,这时候,我们通过人为的规定一种0和1的排列组合顺序为某一种符号或者语言,这就是编码。是一种人为的规定的一种映射集合。想要了解网络安全,学习网络安全知......
  • Java设置JSON字符串参数编码
    1.如何在Java中创建JSON字符串在Java中创建JSON字符串,我们可以使用多个库,其中最流行的是Jackson、Gson和org.json。以下是使用这些库创建JSON字符串的示例:1.1使用Jackson库(1)首先,确保我们的项目中包含了Jackson的依赖(如果我们使用Maven,可以参考前面的示例)。(2)创建一个Java对象(例......
  • 详谈JavaScript 二进制家族:Blob、File、FileReader、ArrayBuffer、Base64
    详谈JavaScript二进制家族:Blob、File、FileReader、ArrayBuffer、Base64:https://blog.csdn.net/weixin_43025151/article/details/129743443?ops_request_misc=&request_id=&biz_id=102&utm_term=JavaScript%E4%B8%AD%E7%9A%84Blob%E4%BD%A0%E7%9F%A5%E9%81%93%E5%A4%9A%E......