我的Java开发学习之旅------Base64的编码思想以及Java实现

Base64是一种用64个字符来表示任意二进制数据的方法。

用记事本打开exe、jpg、pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的文本处理软件能处理二进制数据,就需要一个二进制到字符串的转换方法。Base64是一种最常见的二进制编码方法。


一、编码规则

所谓Base64,就是说选出64个字符----小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"(再加上作为垫字的"=",实际上是65个字符)----作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。

具体来说,转换方式可以分为四步。

  • 第一步,将每三个字节作为一组,一共是24个二进制位。
  • 第二步,将这24个二进制位分为四组,每个组有6个二进制位。
  • 第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节。
  • 第四步,根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值。

注:BASE64字符表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/



Base64 编码表
Value Char
Value Char
Value Char
Value Char
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/



因为,Base64将三个字节转化成四个字节,所以Base64编码后的文本,会比原文本大出三分之一左右。


举一个具体的实例,演示英语单词Man如何转成Base64编码。

文本 M a n
ASCII编码 77 97 110
二进制位 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0
索引 19 22 5 46
Base64编码 T W F u

  • 第一步,"M"、"a"、"n"的ASCII值分别是77、97、110,对应的二进制值是01001101、01100001、01101110,将它们连成一个24位的二进制字符串010011010110000101101110。
  • 第二步,将这个24位的二进制字符串分成4组,每组6个二进制位:010011、010110、000101、101110。
  • 第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节:00010011、00010110、00000101、00101110。它们的十进制值分别是19、22、5、46。
  • 第四步,根据上表,得到每个值对应Base64编码,即T、W、F、u。

因此,Man的Base64编码就是TWFu。


我们看看另外不是刚好是3个字节的情况! 

文本(1 Byte) A

二进制位 0 1 0 0 0 0 0 1















二进制位(补0) 0 1 0 0 0 0 0 1 0 0 0 0











Base64编码 Q Q = =
文本(2 Byte) B C
二进制位 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1

x x x x x x
二进制位(补0) 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 0 0 x x x x x x
Base64编码 Q k M  =

因此,A的Base64编码就是QQ==,BC的Base64编码就是QkM=


 

二、解码规则

      解码过程就是把4个字节再还原成3个字节再根据不同的数据形式把字节数组重新整理成数据。

三、Java实现Base64

public class Base64Utils {/*** 将一个字节数组转换成base64的字符数组* * @param data*            字节数组* @return base64字符数组*/private static char[] encode(byte[] data) {char[] out = new char[((data.length + 2) / 3) * 4];for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {boolean quad = false;boolean trip = false;int val = (0xFF & (int) data[i]);val <<= 8;if ((i + 1) < data.length) {val |= (0xFF & (int) data[i + 1]);trip = true;}val <<= 8;if ((i + 2) < data.length) {val |= (0xFF & (int) data[i + 2]);quad = true;}out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];val >>= 6;out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];val >>= 6;out[index + 1] = alphabet[val & 0x3F];val >>= 6;out[index + 0] = alphabet[val & 0x3F];}return out;}/*** 将一个base64字符数组解码成一个字节数组* * @param data*            base64字符数组* @return 返回解码以后的字节数组*/private static byte[] decode(char[] data) {int len = ((data.length + 3) / 4) * 3;if (data.length > 0 && data[data.length - 1] == '=')--len;if (data.length > 1 && data[data.length - 2] == '=')--len;byte[] out = new byte[len];int shift = 0;int accum = 0;int index = 0;for (int ix = 0; ix < data.length; ix++) {int value = codes[data[ix] & 0xFF];if (value >= 0) {accum <<= 6;shift += 6;accum |= value;if (shift >= 8) {shift -= 8;out[index++] = (byte) ((accum >> shift) & 0xff);}}}if (index != out.length)throw new Error("miscalculated data length!");return out;}/*** base64字符集 0..63*/static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();/*** 初始化base64字符集表*/static private byte[] codes = new byte[256];static {for (int i = 0; i < 256; i++)codes[i] = -1;for (int i = 'A'; i <= 'Z'; i++)codes[i] = (byte) (i - 'A');for (int i = 'a'; i <= 'z'; i++)codes[i] = (byte) (26 + i - 'a');for (int i = '0'; i <= '9'; i++)codes[i] = (byte) (52 + i - '0');codes['+'] = 62;codes['/'] = 63;}/*** 将字符串通过base64转码* @param str 要转码的字符串* @return 返回转码后的字符串*/public static String strToBase64Str(String str){return new String(encode(str.getBytes()));}/*** 将base64码反转成字符串* @param base64Str base64码* @return 返回转码后的字符串*/public static String base64StrToStr(String base64Str){char[] dataArr = new char[base64Str.length()];base64Str.getChars(0, base64Str.length(), dataArr, 0);return new String(decode(dataArr));}/*** 将字节数组通过base64转码* @param byteArray 字节数组* @return 返回转码后的字符串*/public static String byteArrayToBase64Str(byte byteArray[]){return new String(encode(byteArray));}/*** 将base64码转换成字节数组* @param base64Str base64码* @return 返回转换后的字节数组*/public static byte[] base64StrToByteArray(String base64Str){char[] dataArr = new char[base64Str.length()];base64Str.getChars(0, base64Str.length(), dataArr, 0);return decode(dataArr);}/*** @param args* @throws UnsupportedEncodingException */public static void main(String[] args) throws Exception {String strSrc = "Man";String strOut = Base64Utils.strToBase64Str(strSrc);System.out.println("源字符串 "+strSrc+" 的Base64码是:"+strOut);String strOut2 = Base64Utils.base64StrToStr(strOut);System.out.println("Base64码 "+strOut+" 的对应源字符串为:"+strOut2);  byte[] inByteArray={'a','b','c'};String base64Str=Base64Utils.byteArrayToBase64Str(inByteArray);StringBuilder sb=new StringBuilder();sb.append('[');for (int i = 0; i < inByteArray.length; i++) {sb.append(inByteArray[i]+" ");}sb.append(']');System.out.println("字节数组:"+sb+" 的Base64码是:"+base64Str);byte[] outByteArray=Base64Utils.base64StrToByteArray(base64Str);StringBuilder sb2=new StringBuilder();sb2.append('[');for (int i = 0; i < outByteArray.length; i++) {sb2.append(outByteArray[i]+" ");}sb2.append(']');System.out.println("Base64码为"+base64Str+" 的对应字节数组为:"+sb2);}
}

运行效果如下:

源字符串 Man 的Base64码是:TWFu
Base64码 TWFu 的对应源字符串为:Man
字节数组:[97 98 99 ] 的Base64码是:YWJj
Base64码为YWJj 的对应字节数组为:[97 98 99 ]


 



                            ====================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址:http://blog.csdn.net/ouyang_peng

====================================================================================


转载于:https://www.cnblogs.com/ouyangpeng/p/8537979.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296789.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工业领域产品经理的尴尬处境

最近和一个1000人规模公司的智能制造部门进行交流&#xff0c;参会人员包括部门领导、技术人员、产品&#xff08;经理&#xff09;设计人员等&#xff0c;我介绍了工业信息建设相关理念、钢铁云及其他建设案例、iNeuOS工业互联网系统相关内容&#xff0c;交流期间他们领导说了…

【MyBatis-Plus】分页查询

为什么&#xff1f; 使用分页查询&#xff0c;可以将查询结果分割成多个部分&#xff0c;每次只查询部分数据&#xff0c;从而提高性能、减少内存消耗、提高用户体验和数据安全性。 封装分页查询数据类 分页查询的结果通常包含 4 个字段&#xff1a; page&#xff1a;当前页…

android tabhost黑色背景,android更改FragmentTabHost背景和文本颜色

您必须使用操作栏选项卡为每个选项卡获取不同的颜色。MainActivity.java&#xff1a;强>public class MainActivity extends FragmentActivity {static ViewPager Tab;TabsPagerAdapter TabAdapter;ActionBar actionBar;Overrideprotected void onCreate(Bundle savedInstan…

你永远不知道女生裙子下面藏着什么

1 心不是这样比的。。2 这翻墙技巧满分3 盖了我的章你就是我的人了&#xff01;4 论道具组可以穷到什么地步5 你永远不知道女生裙子下面藏着什么6 理发店的赶紧来领你的名片&#xff0c;设计好了&#xff01;7 20190523&#xff0c;就是这样一个本质神奇的日子&#xff01;图自…

ksweb如何安装php5.6_Android端的服务器容器 KSWEB PHP+MySQL环境搭建及应用

1. KSWEBksweb是 一个Android端的服务器容器。有 2.7.2 及 2.8.2 版本&#xff0c;可以用下面链接下载&#xff1a;http://bbs.xiaomi.cn/thread-9690863-1-1.html在Android设备上安装这个apk后&#xff0c;启动就会自动化安装好 php环境和mysql。现在我们就可以在浏览器中输入…

android进程间通信:使用AIDL

android 的binder其实是基于 openbinder实现的&#xff0c;openbinder的地址&#xff1a;http://www.angryredplanet.com/~hackbod/openbinder/docs/html/ http://blog.csdn.net/saintswordsman/article/details/5130947 欢迎阅读本文&#xff0c;你能关注本文&#xff0c;你知…

分布式/微服务必配APM系统,SkyWalking让你不迷路

前言如今分布式、微服务盛行&#xff0c;面对拆分服务比较多的系统&#xff0c;如果线上出现异常&#xff0c;需要快速定位到异常服务节点&#xff0c;假如还用传统的方式排查肯定效率是极低的&#xff0c;因为服务之间的各种通信会让定位更加繁琐&#xff1b;所以就急需一个分…

女程序员的无奈

因为新员工的缘故&#xff0c;最近和新来的女同事做了一次绩效面谈。主要是了解一下学习工作情况&#xff0c;团队融合程度等等。 面谈过程中&#xff0c;明显感觉到她作为女性程序员所特有的一些担心。我大概能理解一下&#xff0c;大概有以下几点&#xff1a; 第一、感觉技术…

HDOJ 3784

继续xxx定律 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1238 Accepted Submission(s): 341 Problem Description当n为3时&#xff0c;我们在验证xxx定律的过程中会得到一个序列&#xff0c;3&#xff0c;5…

gamaredon_Gamaredon组织某样本分析

0x01 Запит СБУ.docx文档分析打开文档后&#xff0c;远程注入模板&#xff1a;文档内容如下&#xff1a;翻译后内容如下&#xff1a;由图标也可以看出&#xff1a;0x02 opt.dot模板分析模板启用了宏&#xff0c;通过olevba.py导出后分析。获取主机ComputerName及系统磁…

JQuery Tree 树形结构插件 zTree

zTree 是利用 JQuery 的核心代码&#xff0c;实现一套能完成大部分常用功能的 Tree 插件兼容 IE、FireFox、Chrome 等浏览器在一个页面内可同时生成多个 Tree 实例支持 JSON 数据支持一次性静态生成 和 Ajax 异步加载 两种方式支持多种事件响应及反馈支持 Tree 的节点移动、编辑…

国外的幼儿数学竟然这样出题?来测测你的孩子都会做吗?

全世界只有3.14 % 的人关注了爆炸吧知识数学很重要&#xff0c;也必须要学&#xff01;在家辅导孩子数学的家长可以在家给宝贝们换张有趣的DIY新试卷&#xff01;孩子玩累了&#xff0c;拿出来做一做&#xff0c;无形中学习数学知识&#xff0c;事半功倍&#xff01;填上对的数…

form配置问题

回发或回调参数无效。在配置中使用 或 在页面中使用 启用了事件验证。出于安全目的&#xff0c;此功能验证回发或回调事件的参数是否来源于最初呈现这些事件的服务器控件。如果数据有效并且是预期的&#xff0c;则使用 ClientScriptManager.RegisterForEventValidation 方法来注…

.NET Core 中如何调试 死锁 ?

这篇文章&#xff0c;我们研究一下如何调试一个 死锁问题&#xff0c;可以下载一下 https://github.com/dotnet/samples/tree/main/core/diagnostics/DiagnosticScenarios 源码&#xff0c;程序运行后&#xff0c;你会发现api无响应而且线程会不断增长&#xff0c;然后你会学习…

ProSolid下的遍历访问封装代码

在ProE二次开发中&#xff0c;时常需要遍历ProSolid下的面、点、轴等几何元素。我们知道&#xff0c;ProToolkit下的遍历函数还是有点小麻烦的&#xff0c;而ProWebLink中就简单很多&#xff0c;比如要遍历某ProSolid下的所有Group&#xff0c;代码如下&#xff1a; 1 var gro…

mybatis 多租户saas_MybatisPlus 多租户架构(SaaS)实现

1. 引言读写分离要做的事情就是对于一条SQL该选择哪个数据库去执行&#xff0c;至于谁来做选择数据库这件事儿&#xff0c;无非两个&#xff0c;要么中间件帮我们做&#xff0c;要么程序自己做。因此&#xff0c;一般来讲&#xff0c;读写分离有两种实现方式。第一种是依靠中间…

Floodlight 在 ChannelPipeline 图

我们知道&#xff0c;在Netty架构&#xff0c;一个ServerBootstrap用于生成server端的Channel的时候都须要提供一个ChannelPipelineFactory类型的參数&#xff0c;用于服务于建立连接的Channel&#xff0c;流水线处理来自某个client的请求。所以这里的 OpenflowPipelineFactory…

html超文本链接本页面,从HTML语言到网上家园 第三章 超文本链接(1)-网页设计,HTML/CSS...

超文本链接是 html 语言最大的特点之一&#xff0c;使用超文本链接可以极大的增加文件访问的灵活度&#xff0c;人们可以通过点击页面中的链接指针查看所需的内容&#xff0c;进退自如&#xff0c;灵活方便&#xff0c;这更加符合人的跳跃、交叉的思维方式。凡是浏览过网页的人…

PS景观彩色平面图技巧

1、关于水系&#xff0c;园林学习网 PS景观彩色平面图 水要有阴影&#xff0c;不过是内投影。可以用图层特效来做&#xff0c;也可以用高斯模糊。 要有光感&#xff0c;可以用退晕&#xff0c;也可以用滤镜打光。 2、草地 草地在红线内外一定要区分开色象和明度饱和度&#xff…

牛顿如果穿越到现在,能看懂相对论和量子力学吗?

全世界只有3.14 % 的人关注了爆炸吧知识今天要讲给大家讲一个从朋友BOSS那里听来的故事&#xff0c;而故事的主人公就是赫赫有名的牛顿大神。话说那一天&#xff0c;BOSS在牛顿的苹果树下思考人生。突然牛顿就从苹果树下的棺材里爬了出来&#xff0c;棺材板怎么压都压不住。于是…