我的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 0 A 16 Q 32 g 48 w 1 B 17 R 33 h 49 x 2 C 18 S 34 i 50 y 3 D 19 T 35 j 51 z 4 E 20 U 36 k 52 0 5 F 21 V 37 l 53 1 6 G 22 W 38 m 54 2 7 H 23 X 39 n 55 3 8 I 24 Y 40 o 56 4 9 J 25 Z 41 p 57 5 10 K 26 a 42 q 58 6 11 L 27 b 43 r 59 7 12 M 28 c 44 s 60 8 13 N 29 d 45 t 61 9 14 O 30 e 46 u 62 + 15 P 31 f 47 v 63 /
因为,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/8537980.html
我的Java开发学习之旅------Base64的编码思想以及Java实现相关推荐
- 我的Java开发学习之旅------gt;Base64的编码思想以及Java实现
Base64是一种用64个字符来表示任意二进制数据的方法. 用记事本打开exe.jpg.pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的 ...
- 我的Java开发学习之旅------JAVA 笔记ClassLoader.getResourceAsStream() 与 Class.getResourceAsStream()的区别...
今天,一读者在我的 Android通过调用Webservice实现手机号码归属地查询 文章中给我回复了一个问题,由于没有具体说明我的sop12.xml文件是放在src目录下,不是和具体操作类Addre ...
- 我的Java开发学习之旅------求字符串中出现次数最多的字符串以及出现的次数...
金山公司面试题:一个字符串中可能包含a~z中的多个字符,如有重复,如String data="aavzcadfdsfsdhshgWasdfasdf",求出现次数最多的那个字母及次数 ...
- 我的Java开发学习之旅------心得总结:Java性能优化技巧集锦
一.通用篇 "通用篇"讨论的问题适合于大多数Java应用. 1.1 不用new关键词创建类的实例 用new关键词创建类的实例时,构造函数链中的所有构造函数都会被自动调用.但如果一个 ...
- 我的Java开发学习之旅------Java资源的国际化详解
internationalization (国际化)简称 i18n,因为在i和n之间还有18个字符,localization(本地化 ),简称L10n. 国际化相关的Java类 Java国际化主要通过 ...
- 【我的Java开发学习之旅】Windows系统下如何运行.jar文件?
一.需求描述 今天查询大数据平台,看到刚刚发布的APP版本有crash,然后平台上的crash都是混淆的样子,类似如下所示: 所以我得使用proguardgui.jar工具来进行反混淆,查看出现问题的 ...
- 我的Java开发学习之旅------gt;Java经典排序算法之希尔排序
一.希尔排序(Shell Sort) 希尔排序(Shell Sort)是一种插入排序算法,因D.L.Shell于1959年提出而得名. Shell排序又称作缩小增量排序. 二.希尔排序的基本思想 希尔 ...
- 我的Java开发学习之旅------Java经典排序算法之希尔排序
一.希尔排序(Shell Sort) 希尔排序(Shell Sort)是一种插入排序算法,因D.L.Shell于1959年提出而得名. Shell排序又称作缩小增量排序. 二.希尔排序的基本思想 希尔 ...
- 我的Java开发学习之旅------Java经典排序算法之二分插入排序
一.折半插入排序(二分插入排序) 将直接插入排序中寻找A[i]的插入位置的方法改为采用折半比较,即可得到折半插入排序算法.在处理A[i]时,A[0]--A[i-1]已经按关键码值排好序.所谓折半比较, ...
最新文章
- IOS网络篇1之截取本地URL请求(NSURLProtocol)
- 导入CSS的三种方式
- CTFshow 信息收集 web18
- php 多维素组添加下级,php中如何将元素添加到多维数组
- nyist 132Prime Ring Problem
- ML2 配置 OVS VxLAN - 每天5分钟玩转 OpenStack(146)
- 【Java】探究Java方法的参数传递是值传递还是引用传递
- 百度搜索引擎优化指南_百度SEO优化和其他搜索引擎优化用什么不同的地方
- Colidity-- Dominator
- 未能加载文件或程序集“Newtonsoft.Json”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)...
- MVC3+EF4.1学习系列(五)----- EF查找导航属性的几种方式
- 使用计算机眼睛保护方法有哪些,​计算机族的“护眼诀窍”
- 前方高能预警!三星Galaxy A6s带你闹元旦
- 怎么在一张图片中隐藏文件?
- Spring Boot 的配置文件有哪几种格式?它们有什么区别?
- 怎么样成为一名Python工程师?到底要会哪些东西?你会了多少?
- append()函数
- ibatis mysql存储过程_分步详解 如何在iBatis中调用存储过程
- 免费下载思科CCNP 642-353考试题库
- 宽带连接错误的处理办法651、691、623、678、645、720、721、718、734、769