我的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;交流期间他们领导说了…

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

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

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

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

JQuery Tree 树形结构插件 zTree

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

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

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

ProSolid下的遍历访问封装代码

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

Floodlight 在 ChannelPipeline 图

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

PS景观彩色平面图技巧

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

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

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

02Prism WPF 入门实战 - 建项

1.概要Prism介绍Github: https://github.com/PrismLibrary/Prism开发文档&#xff1a;https://prismlibrary.com/docs/Prism是一个框架&#xff0c;用于在WPF、Xamarin Forms、Uno Platform和WinUI中构建松散耦合、可维护和可测试的XAML应用程序。设计目标 为了实现下列目的&a…

html首页 slider图片切换效果,jQuery插件Slider Revolution实现响应动画滑动图片切换效果...

jQuery插件Slider Revolution实现响应动画滑动图片切换效果2018-12-31编程之家https://www.jb51.cc这是一款非常强大的内容切换插件&#xff0c;它基于jQuery&#xff0c;它充分响应&#xff0c;支持移动设备&#xff0c;支持手机触摸&#xff0c;键盘翻页&#xff1b;它内置幻…

大数据告诉你:学历真的能改变命运!!

全世界只有3.14 % 的人关注了爆炸吧知识央视新闻曾做过关于高考的调查&#xff0c;结果有七成网友支持高考取消数学&#xff0c;看到新闻后&#xff0c;有一位网友却一针见血地评论道&#xff1a;数学考试存在的意义就是把这七成网友筛选掉。的确&#xff0c;虽然买菜不需要专业…

小米8ios图标包下载_小米互传PC端抢先下载,免流量、高速互传,支持多设备共享...

小米早在MIUI初期就已经在开始探索手机与电脑之间互传文件的问题&#xff0c;MIUI"无线数据线"功能一直备受喜欢。手机与电脑之间互传&#xff0c;90%的用户都选择使用WX或者QQ来实现&#xff0c;它们互传的通道是互联网&#xff0c;无网时不可使用。为解决这个问题&…

HTML怎么做类似QQ聊天气泡,h5实现QQ聊天气泡的实例介绍

这篇文章主要介绍了HTML5实现QQ聊天气泡效果&#xff0c;用 HTML/CSS 做了个类似QQ的聊天气泡&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下今天自己用 HTML/CSS 做了个类似QQ的聊天气泡&#xff0c;以下是效果图&#xff1a;以下说下关键地方的样式…

高等数学的用处之一

1 只能说计算的真精准2 龙虾&#xff1a;我都准备半天了&#xff0c;你俩到底上不上&#xff1f;3 猫(≧^.^≦)&#xff1a;我为这个宿舍付出太多了&#xff01;4 请举一个日常生活中利用高等数学来解决问题的案例。5 男生做什么会让女生不开心7 人家拍的泸沽湖的水性杨花和我拍…

Fiddler抓包一键生成调用代码

首先我们的需求场景是用Fiddler抓到某个接口调用后&#xff0c;用代码来模拟调用&#xff0c;一般我们写代码会有3个步骤&#xff1a;1设置http请求相关的参数:header,method,url,cookie等2设置post的body(如果是post的话需要)3拿到返回的body(一般我们需要拿到接口的返回体进行…

DexClassLoader的使用

版权声明&#xff1a;您好&#xff0c;转载请留下本人博客的地址&#xff0c;谢谢 https://blog.csdn.net/hongbochen1223/article/details/47146613 在Java环境中,有个概念叫做”类装载器(Class Loader)”,其作用是动态加载Class文件.标准的Java SDK中有一个ClassLoader类,借助…

这才是老公的正确用法,不吃就往死里打......

1 倒是好办法就是有点儿费爸爸▼2 一只被主人遗弃的小熊的奇幻旅程▼3 小子&#xff0c;你单身的命运gu7在你把美女老师撂倒那一刻就注定了...▼4 张萌姐姐自我肯定式唱歌▼5 &#xff1f;&#xff1f;&#xff1f;有被冒犯到▼6 听说昨天有个少年28岁就退休了▼7 哪个男…

C# WPF MVVM模式下在主窗体显示子窗体并获取结果

01—前言在winform中打开一个新的子窗体很简单&#xff0c;直接实例化窗体并show一下就可以&#xff1a;Form2 f2 new Form2();f2.Show();或者Form2 f2 new Form2();f2.ShowDialog();但是&#xff0c;在wpf的mvvm模式下&#xff0c;这种方法是行不通的&#xff0c;因为逻辑是…

Exchange 2010发现拓扑失败

今天跟大家继续分享一个我在项目中遇到的问题哈&#xff0c;希望对大家今后的项目排错有帮助。问题背景&#xff1a;企业主域控从 Window Server 2003升级为Windows Server 2012 R2具体实施方法可以参考我之前的文章(http://horse87.blog.51cto.com/2633686/1613268)在顺利升级…