netty 系列之:java 中的 base64 编码器

2023-10-29

 

简介

什么是 Base64 编码呢?在回答这个问题之前,我们需要了解一下计算机中文件的分类,对于计算机来说文件可以分为两类,一类是文本文件,一类是二进制文件。

对于二进制文件来说,其内容是用二进制来表示的,对于人类是不可立马理解的。如果你尝试用文本编辑器打开二进制文件,可能会看到乱码。这是因为二进制文件的编码方式和文本文件的编码方式是不一样的,所以当文本编辑器尝试将二进制文件翻译成为文本内容的时候,就会出现乱码。

对于文本文件来说,也有很多种编码方式,比如最早的 ASCII 编码和目前常用的 UTF-8 和 UTF-16 等编码方式。即使是文本文件,如果你使用不同的编码方式打开,也可能会看到乱码。

所以不管是文本文件还是二进制文件也好,都需要进行编码格式的统一。也就是说写入的编码是什么样子的,那么数据读取的编码也应该和其匹配。

Base64 编码实际上就是将二进制数据编码成为可视化 ASCII 字符的一种编码方式。

为什么会有这样的要求呢?

我们知道计算机世界的发展不是一蹴而就的,它是一个慢慢成长的过程,对于字符编码来说,最早只支持 ASCII 编码,后面才扩展到 Unicode 等。所以对于很多应用来说除了 ASCII 编码之外的其他编码格式是不支持的,那么如何在这些系统中展示非 ASCII code 呢?

解决的方式就是进行编码映射,将非 ASCII 的字符映射成为 ASCII 的字符。而 base64 就是这样的一种编码方式。

常见的使用 Base64 的地方就是在 web 网页中,有时候我们需要在网页中展示图片,那么可以将图片进行 base64 编码,然后填充到 html 中。

还有一种应用就是将文件进行 base64 编码,然后作为邮件的附件进行发送。

JAVA 对 base64 的支持

既然 base64 编码这么好用,接下来我们来看一下 JAVA 中的 base64 实现。

java 中有一个对应的 base64 实现,叫做 java.util.Base64。这个类是 Base64 的工具类,是 JDK 在 1.8 版本引入的。

Base64 中提供了三个 getEncoder 和 getDecoder 方法,通过获取对应的 Encoder 和 Decoder,然后就可以调用 Encoder 的 encode 和 decode 方法对数据进行编码和解码,非常的方便。

我们先来看一下 Base64 的基本使用例子:

 // 使用encoder进行编码 String encodedString = Base64.getEncoder().encodeToString("what is your name baby?".getBytes("utf-8")); System.out.println("Base64编码过后的字符串 :" + encodedString);
 // 使用encoder进行解码 byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
 System.out.println("解码过后的字符串: " + new String(decodedBytes, "utf-8"));

作为一个工具类,JDK 中提供的 Base64 工具类还是很好用的。

这里就不详细讲解它的使用,本篇文章主要分析 JDK 中 Base64 是怎么实现的。

JDK 中 Base64 的分类和实现

JDK 中 Base64 类有提供了三个 encoder 方法,分别是 getEncoder,getUrlEncoder 和 getMimeEncoder:

    public static Encoder getEncoder() {         return Encoder.RFC4648;    }
    public static Encoder getUrlEncoder() {         return Encoder.RFC4648_URLSAFE;    }
    public static Encoder getMimeEncoder() {        return Encoder.RFC2045;    }

同样的,它也提供了三个对应的 decoder,分别是 getDecoder,getUrlDecoder,getMimeDecoder:

    public static Decoder getDecoder() {         return Decoder.RFC4648;    }
    public static Decoder getUrlDecoder() {         return Decoder.RFC4648_URLSAFE;    }
    public static Decoder getMimeDecoder() {         return Decoder.RFC2045;    }

从代码中可以看出,这三种编码分别对应的是 RFC4648,RFC4648_URLSAFE 和 RFC2045。

这三种都属于 base64 编码的变体,我们看下他们有什么区别:

可以看到 base64 和 Base64url 的区别是第 62 位和第 63 位的编码字符不一样,而 base64 for MIME 跟 base64 的区别是补全符是否是强制的。

另外,对于 Basic 和 base64url 来说,不会添加 line separator 字符,而 base64 for MIME 在一行超出 76 字符之后,会添加'\r' 和 '\n'作为 line separator。

最后,如果在解码的过程中,发现有不存于 Base64 映射表中的字符的处理方式也不一样,base64 和 Base64url 会直接拒绝,而 base64 for MIME 则会忽略。

base64 和 Base64url 的区别可以通过下面两个方法来看出:

        private static final char[] toBase64 = {            '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',            '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', '6', '7', '8', '9', '+', '/'        };
        private static final char[] toBase64URL = {            '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',            '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', '6', '7', '8', '9', '-', '_'        };

而对 MIME 来说,定义了一个一行的最大字符个数,和换行符:

        private static final int MIMELINEMAX = 76;        private static final byte[] CRLF = new byte[] {'\r', '\n'};

Base64 的高级用法

一般情况下我们用 Base64 进行编码的对象长度是固定的,我们只需要将输入对象转换成为 byte 数组即可调用 encode 或者 decode 的方法。

但是在某些情况下我们需要对流数据进行转换,这时候就可以用到 Base64 中提供的两个对 Stream 进行 wrap 的方法:

        public OutputStream wrap(OutputStream os) {            Objects.requireNonNull(os);            return new EncOutputStream(os, isURL ? toBase64URL : toBase64,                                       newline, linemax, doPadding);        }
        public InputStream wrap(InputStream is) {            Objects.requireNonNull(is);            return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);        }

这两个方法分别对应于 encoder 和 decoder。

总结

以上就是 JDK 中对 Base64 的实现和使用,虽然 base64 的变种有很多种,但是 JDK 中的 Base64 只实现了其中用处最为广泛的 3 种。大家在使用的时候一定要区分具体是那种 Base64 的实现方式,以免出现问题。

需要点化的小伙伴请点赞收藏+评论转发+关注我之后私信我,注意回复【000】即可获取更多免费资料!

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

netty 系列之:java 中的 base64 编码器 的相关文章

随机推荐

  • 软件交付质量复盘与注意事项

    软件交付质量 在日常的工作流程中 比较通用的流程如下图所示 从质量保障和交付的角度来讲 软件交付生命周期中大体可分为如下三个阶段 需求设计质量 这个阶段包括原型图 PRD文档 交互设计 技术方案 测试用例等几项重要产出物 当然他们有一定的前
  • Spring Boot 实现定时任务动态管理,太爽了!

    一 功能说明 SpringBoot的定时任务的加强工具 实现对SpringBoot原生的定时任务进行动态管理 完全兼容原生 Scheduled注解 无需对原本的定时任务进行修改 二 快速使用 具体的功能已经封装成SpringBoot sta
  • yolov5 烟雾和火焰检测

    视频实时多人姿态估计 cpu fps33 实时视频动作检测 action detection 基于人体姿态的跌倒检测 yolov5 烟雾和火焰检测 文章用到的云gpu详细使用说明 随着社会经济的高速发展 工业 企业园区 住宅日益增多 存在一
  • 交叉编译eigen3.2.10至ARM架构

    交叉编译eigen3 2 10至ARM架构 1 下载交叉编译链 PC机为x86架构 目标平台为ARM架构 首先需要安装x86至ARM平台的交叉编译链 需要注意的是 编译链上C库的版本需要和目标平台上的C库版本兼容 我起初参考其他博客直接ap
  • 运放分析--虚短与虚断

    虚短与虚断 1 虚短 如图1所示 虚短是指运放的输入端V 和V 可视为电压差很小 即近似相等 V V 由于并没有实际的物理连接 故我们称其为虚短 以区别物理连接的短路 若其中一端接地 则另一端在必要时 可认为虚地 2 虚断 由于运放是高阻抗
  • ScheduledThreadPoolExecutor 线程池例子

    ScheduledThreadPoolExecutor 线程池例子 一 ScheduledThreadPoolExecutor 使用 1 使用示例 提交任务 简单例子 二 ScheduledThreadPoolExecutor 原理 1 D
  • android状态栏一体化(沉浸式状态栏)

    Android 沉浸式状态栏 状态栏一体化 透明状态栏 仿ios透明状态栏 http blog csdn net jdsjlzx article details 50437779 注 状态栏的字体颜色位白色 如果状态栏背景为白色 上面的博客
  • Easyui入门(二)

    Easyui入门之Tree后台实现 tree的组件简介 案例1 运行结果 2 tree组件工具类的实现思路 预热 方案 代码 链接 代码2 正式从数据库拿数据写 代码 代码2 总结 tree的组件简介 静态的html方式 缺点 如果树形结构
  • C++中类的静态成员变量

    在C语言中 我们知道有static静态变量 生命周期与作用域都跟普通变量有所不同 而在C 的类中 也有静态成员变量同时还有静态成员函数 先来看看C 中静态成员变量与静态成员函数的语法 include
  • 润和软件推出HarmonyOS物联网系列模组Neptune,助力Harmony生态

    在2020 第十七届 中国物联网产业大会上 HarmonyOS首批官方合作伙伴润和软件宣布推出HarmonyOS智能硬件新品 支持HarmonyOS的物联网系列模组Neptune HH SLNPT10x 该系列模组使用的芯片由润和软件HiH
  • C语言,打印杨辉三角

    include
  • 【编译原理】三地址码

    三地址码 编译器构造 编译器的结构 中间语言 中间语言表达式 逆波兰 RPN 形式 图形 语义树 三地址码表达形式 四地址码表达形式 三地址码 三地址码 TAC 指令 三地址码的使用和特点 文字表 优化阶段 编译器构造 编译器的结构 语义检
  • powershell get-date计算指定日期及格式化

    get date format yyyyMMdd 获取当天日期并格式化为20200107的格式 get date UFormat V 获取当天是本年度的第几周 这里有一个bug 就是每周一获取到的还是上周 get date adddays
  • Ant-Design-Pro小试:react开发步骤(mock数据)

    1 router config js path train name train icon profile routes profile path train list name list component Train List 2 me
  • object-c万能解决bug思路

    有关运算符重载 C 支持运算符重载 但 Objective C 中不支持 然而 Objc 中可以看到下面的用法 id obj dict keyStr 它和 id obj dict objectForKey keyStr 等价 这里的 的用法
  • java综合技术分享

    1 心跳机制 1 1心跳包机制 跳包之所以叫心跳包是因为 它像心跳一样每隔固定时间发一次 以此来告诉服务器 这个客户端还活着 事实上这是为了保持长连接 至于这个包的内容 是没有什么特别规定的 不过一般都是很小的包 或者只包含包头的一个空包
  • stack queue free-lock implate

    https github com kayaklee libhalog blob master test clib hv sample lifo cpp https github com kayaklee libhalog blob mast
  • thrift源码解析之server

    文章目录 前言 概述 TSimpleServer serve 1 listen 2 accept 3 newlyConnectedClient TNonblockingServer serve 1 registerEvents 1 赋值us
  • Java中Thread类的基本用法

    目录 一 创建线程的方式 1 继承Thread类 2 实现Runnable接口 3 匿名内部类中创建Thread子类对象 4 匿名内部类中创建Runnable子类对象 5 lambda表达式创建Runnabl子类对象 二 Thread的常见
  • netty 系列之:java 中的 base64 编码器

    简介 什么是 Base64 编码呢 在回答这个问题之前 我们需要了解一下计算机中文件的分类 对于计算机来说文件可以分为两类 一类是文本文件 一类是二进制文件 对于二进制文件来说 其内容是用二进制来表示的 对于人类是不可立马理解的 如果你尝试