我的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
====================================================================================
我的Java开发学习之旅------>Base64的编码思想以及Java实现的更多相关文章
- 我的Java开发学习之旅------>Java 格式化类(java.util.Formatter)基本用法
本文参考: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html http://www.blogjava.net/ ...
- 我的Java开发学习之旅------>工具类:将播放器的进度值转换成相应的时间格式
在我的博客<我的Java开发学习之旅------>Java 格式化类(java.util.Formatter)基本用法,地址:http://blog.csdn.net/ouyang_pen ...
- 我的Java开发学习之旅------>在Dos环境下Java内部类的编译和运行
习惯了在IDE工具上进行代码编写,连最基本的Javac命令和Java命令都忘记的差不多了,今天对一个Java内部类进行编译和运行的时候,就出糗了.IDE是把双刃剑,它可以什么都帮你做了,你只要敲几行代 ...
- 我的Java开发学习之旅------>工具类:Java获取字符串和文件进行MD5值
ps:这几天本人用百度云盘秒传了几部大片到云盘上,几个G的文件瞬秒竟然显示"上传成功"!这真让我目瞪口呆,要是这样的话,那得多快的网速,这绝对是不可能的,也许这仅是个假象.百度了一 ...
- 我的Java开发学习之旅------>工具类:Java使用正则表达式分离出字符串中的中文和英文
今天看到一个工具类使用正则表达式将一大段字符串中的中文和英文都分离出来了,在此记录一下,读者可以收藏! import java.util.ArrayList; import java.util.Col ...
- 我的Java开发学习之旅------>Java利用Comparator接口对多个排序条件进行处理
一需求 二实现Comparator接口 三验证排序结果 验证第一条件首先按级别排序级别最高的排在前面 验证第二条如果级别相等那么按工资排序工资高的排在前面 验证第三条如果工资相当则按入职年数排序入职时 ...
- 我的Java开发学习之旅------>二进制、八进制、十进制、十六进制之间转换
一. 十进制与二进制之间的转换 (1) 十进制转换为二进制,分为整数部分和小数部分 ① 整数部分 方法:除2取余法,即每次将整数部分除以2,余数为该位权上的数,而商继续除以2,余数又为上一个位权 ...
- 我的Java开发学习之旅------>Base64的编码思想以及Java实现
Base64是一种用64个字符来表示任意二进制数据的方法. 用记事本打开exe.jpg.pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的 ...
- 我的Java开发学习之旅------>System.nanoTime与System.currentTimeMillis的区别
首先来看一道题:下面代码的输出结果是什么? import java.util.HashMap; import java.util.Map; public class HashMapTest { pub ...
随机推荐
- 通讯框架 T-io 学习——给初学者的Demo:ShowCase设计分析
前言 最近闲暇时间研究Springboot,正好需要用到即时通讯部分了,虽然springboot 有websocket,但是我还是看中了 t-io框架.看了部分源代码和示例,先把helloworld敲 ...
- Apache降权和禁用PHP危险函数
测试环境: Windows Server 2003 + phpstudy 首先在win2003里运行phpstudy,这里注意需要选择应用系统服务模式,应用之后重启phpstudy. 打开系统服务(开 ...
- 5. 监视和ZooKeeper操作
ZooKeeper中的写入(write)操作是原子性和持久性的. 写入到大多数ZooKeeper服务器上的持久性存储中,可以保证写操作成功. 无论如何,ZooKeeper的最终一致性模型允许读取(re ...
- vmware中Ubuntu不能全屏展示的问题
依次打开system settings---------------->Displays----------------->resoluiton调整分辨率,然后右下角点击apply,然后k ...
- JVM命令
jstack--jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息: jinfo--jinfo可以输出并修改运行时的java 进程的opts.用处比较简单 ...
- 查看oracle数据库里哪些语句耗时最长或者效率最低
CPU: select * from (select v.sql_id, v.child_number, v.sql_text, v.elapsed_time, v.cpu_time, v.disk_ ...
- Java并发之线程管理(线程基础知识)
因为书中涵盖的知识点比较全,所以就以书中的目录来学习和记录.当然,学习书中知识的时候自己的思考和实践是最重要的.说到线程,脑子里大概知道是个什么东西,但很多东西都还是懵懵懂懂,这是最可怕的.所以想着细 ...
- SQLServer2008数据库连接error40错误
在连接SQL Server偶尔会遇到报错,如在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误.未找到或无法访问服务器.请验证实例名称是否正确并且 SQL Server 已配置为 ...
- 详解卷积神经网络(CNN)在语音识别中的应用
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:侯艺馨 前言 总结目前语音识别的发展现状,dnn.rnn/lstm和cnn算是语音识别中几个比较主流的方向.2012年,微软邓力和俞栋老 ...
- java基础回顾(一)
java的特点:开源.安全.跨平台.简单易懂.一次编译可多处运行. JDK:java开发工具包 JDK = JRE+JAVA开发工具 保证能够实现java开发的最小单元 JRE:java运行环境 JR ...