Base64的Java代码实现
欢迎拍砖~
在数据二进制和byte互相转换的地方方法写得有点挫,不知道有没有更好的方法~
顺便复习了java的一些基础东西,如位操作,原码反码补码
可以在这篇blog里学习到详细的知识点:http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html
直接上代码吧,知识点在注释上
编码器:
- package jdbc.pro.lin;
- import java.util.HashMap;
- import java.util.Map;
- public class MyBase64Encoder {
- private static final Map<Integer, Character> INDEX_MAP = new HashMap<Integer, Character>();
- private static final char PADDING_CHAR = '=';
- static {
- int index = 0;
- for (int i = 0; i <= 25; i++) {
- INDEX_MAP.put(index, (char) ((int) 'A' + i));
- index++;
- }
- for (int j = 0; j <= 25; j++) {
- INDEX_MAP.put(index, (char) ((int) 'a' + j));
- index++;
- }
- for (int k = 0; k <= 9; k++) {
- INDEX_MAP.put(index, (char) ((int) '0' + k));
- index++;
- }
- INDEX_MAP.put(index, '+');
- index++;
- INDEX_MAP.put(index, '/');
- }
- public static String encode(byte[] bytes) throws Exception {
- /**
- * 1.转成二进制的字符串(长度为6的倍数)
- * 2.获取转义后的字符串
- * 3.不是4的位数,填充=号
- */
- String binaryString = convertByteArray2BinaryString(bytes);
- String escapeString = escapeBinaryString(binaryString);
- return paddingEscapeString(escapeString);
- }
- private static String convertByteArray2BinaryString(byte[] bytes) {
- StringBuilder binaryBuilder = new StringBuilder();
- for (byte b : bytes) {
- binaryBuilder.append(convertByte2BinaryString(b));
- }
- int paddingCount = binaryBuilder.length() % 6;
- int totalCount = paddingCount > 0 ? binaryBuilder.length() / 6 + 1
- : binaryBuilder.length() / 6;
- int actualLength = 6 * totalCount;
- //百分号后面的-号表示长度不够规定长度时,右填充。否则左填充。
- return String.format("%-" + actualLength + "s",
- binaryBuilder.toString()).replace(' ', '0');
- }
- private static String escapeBinaryString(String binaryString)
- throws Exception {
- if (null == binaryString || binaryString.isEmpty()
- || binaryString.length() % 6 != 0) {
- System.out.println("error");
- throw new Exception("escape binary string error.");
- }
- StringBuilder escapeBuilder = new StringBuilder();
- for (int i = 0; i <= binaryString.length() - 1; i += 6) {
- String escapeString = binaryString.substring(i, i + 6);
- int index = Integer.parseInt(escapeString, 2);
- escapeBuilder.append(INDEX_MAP.get(index));
- }
- return escapeBuilder.toString();
- }
- private static String paddingEscapeString(String escapeString) {
- int paddingCount = escapeString.length() % 4;
- int totalCount = paddingCount > 0 ? escapeString.length() / 4 + 1
- : escapeString.length() / 4;
- int actualCount = 4 * totalCount;
- return String.format("%-" + actualCount + "s", escapeString).replace(
- ' ', PADDING_CHAR);
- }
- private static String convertByte2BinaryString(byte b) {
- /**
- * 对于非负数,直接使用Integer.toBinaryString方法把它打印出来
- */
- if (b >= 0) {
- StringBuilder builder = new StringBuilder();
- builder.append(Integer.toBinaryString(b));
- return String.format("%08d", Integer.parseInt(builder.toString()));
- } else {
- /**
- * 对于负数,要记住内存保存的是补码。
- * 不能直接使用Byte.parseByte()方法。
- * 因为这个方法最终调的是Integer.parseInt()方法,也就是说,负数如:10000001
- * 对Integer.parseInt()来说并不会认为是负数,符号位1被当作数值位,是129
- * 同时Byte.parseByte()方法里还对数值范围做了校验,符号位1,已超出范围,这样
- * 会抛出异常。而Byte又没有提供toBinaryString的方法
- * 为了保存byte的二进制值,可利用按位与的方法
- * 例如有一个负数1000 1111,要把它以字符串保留出来,利用它与1111 1111的与操作,
- * 再转成int类型。1000 1111 & 1111 1111
- * 在内存中保存的就是 00000000 10001111,这时保存的是一个正整数。但我们不关心整数的正负,
- * 因为我们的目的是要把这串字符串截取出来
- * 再利用Integer.toBinaryString()打印出来。
- * Integer.toBinaryString()对于正数,会将前面的零去掉,如上将打印出1000 1111,这就是我们要的结果。
- */
- int value = b & 0xFF;
- return Integer.toBinaryString(value);
- }
- }
- }
解码器:
- package jdbc.pro.lin;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- public class MyBase64Decoder {
- private static final char PADDING_CHAR = '=';
- private static final Map<Character, Integer> VALUE_MAP = new HashMap<Character, Integer>();
- static {
- int index = 0;
- for (char i = 'A'; i <= 'Z'; i++, index++) {
- VALUE_MAP.put(i, index);
- }
- for (char j = 'a'; j <= 'z'; j++, index++) {
- VALUE_MAP.put(j, index);
- }
- for (char k = '0'; k <= '9'; k++, index++) {
- VALUE_MAP.put(k, index);
- }
- VALUE_MAP.put('+', index);
- index++;
- VALUE_MAP.put('/', index);
- }
- public static byte[] decode(String base64String) {
- if (null == base64String || base64String.isEmpty()) {
- return null;
- }
- /**
- * 1.去掉末尾拼凑的=符号 2.转成二进制 3.去掉末尾拼凑的0 4.截取每8位取数
- */
- base64String = removePaddingChar(base64String);
- String binaryString = getBinaryString(base64String);
- binaryString = removePaddingNumber(binaryString);
- return convertBinaryString2Bytes(binaryString);
- }
- /**
- * 删除末尾拼凑的=符号
- *
- * @param base64String
- * @return
- */
- private static String removePaddingChar(String base64String) {
- int firstPaddingIndex = base64String.indexOf(PADDING_CHAR);
- return firstPaddingIndex >= 0 ? base64String.substring(0,
- firstPaddingIndex) : base64String;
- }
- /**
- * 将base64字符串转成二进制字符串
- *
- * @param base64String
- * @return
- */
- private static String getBinaryString(String base64String) {
- StringBuilder binaryBuilder = new StringBuilder();
- for (char c : base64String.toCharArray()) {
- int value = VALUE_MAP.get(c);
- binaryBuilder.append(String.format("%6s",
- Integer.toBinaryString(value)).replace(" ", "0"));
- }
- return binaryBuilder.toString();
- }
- /**
- * 二进制字符串中的末尾有一些0是因为不足6的倍数而填充的,需要删除
- *
- * @param binaryString
- * @return
- */
- private static String removePaddingNumber(String binaryString) {
- int remainder = binaryString.length() % 8;
- binaryString = binaryString.substring(0, binaryString.length()
- - remainder);
- return binaryString;
- }
- private static byte[] convertBinaryString2Bytes(String binaryString) {
- if (null == binaryString || binaryString.length() % 8 != 0) {
- System.out.println("binary string not well formatted.");
- return null;
- }
- int size = binaryString.length() / 8;
- byte[] bytes = new byte[size];
- int arrayIndex = 0;
- for (int i = 0; i <= binaryString.length() - 1; i += 8, arrayIndex++) {
- String byteString = binaryString.substring(i, i + 8);
- /**
- * 非负数,直接使用Byte.parseByte()方法
- */
- if (byteString.startsWith("0")) {
- bytes[arrayIndex] = Byte.parseByte(byteString, 2);
- } else {
- /**
- * 10000000为-128是规定而来的。 -128并没有原码和反码表示。对-128的补码表示[10000000]补
- * 算出来的原码是[0000 0000]原, 这是不正确的)
- */
- if (byteString.equals("1000000")) {
- bytes[arrayIndex] = (byte) -128;
- continue;
- }
- /**
- * 其他的负数,就要按照补码的规则来计算 即,原码取反+1=补码 那么,补码-1取反=原码
- * 注意这都是真值部分的计算,符号位不能变
- */
- // 补码
- String twosComplement = byteString.substring(1);
- byte twoComplementValue = Byte.parseByte(twosComplement, 2);
- // 反码
- byte oneComplementValue = (byte) (twoComplementValue - 1);
- /**
- * 这里用到的是0x7F而不是0xFF。因为oneComplementValue是0开头
- * 若与1开头的异或,结果为1,而在int中该位不是符号位,会当成数值计算,造成数值错误。
- * 因此,必须结果是0,即,两个0的异或。
- */
- // 真值 8位的计算
- int trueValue = oneComplementValue ^ 0x7F;
- bytes[arrayIndex] = (byte) (trueValue * (-1));
- }
- }
- return bytes;
- }
- }
测试代码:
- package jdbc.pro.lin;
- import oracle.net.aso.i;
- import org.apache.commons.codec.binary.Base64;
- public class TestMain {
- public static void main(String[] args) throws Exception {
- byte[] binaryData = { 0, -2, -128, 127, 1, -1, 3, 4, 89, 45, 0 };
- String thirdPartyBase64String = Base64.encodeBase64String(binaryData);
- String myBase64String = MyBase64Encoder.encode(binaryData);
- System.out.println("ThirdParty encode: " + thirdPartyBase64String);
- System.out.println("MyBase64 encode: " + myBase64String);
- System.out.print("ThirdParty decode: ");
- printBytes(Base64.decodeBase64(thirdPartyBase64String.getBytes()));
- System.out.print("MyBase64 decode: ");
- printBytes(MyBase64Decoder.decode(thirdPartyBase64String));
- }
- private static void printBytes(byte[] bytes) {
- for (byte b : bytes) {
- System.out.print(b);
- System.out.print(" ");
- }
- System.out.println("");
- }
- }
测试结果:
附Byte.parseByte()的反编译源码,确实是调用了Integer.parseInt()方法,导致符号位失效,对于10001111这样的数值认为是正数
Base64的Java代码实现的更多相关文章
- Java Base64加密、解密原理Java代码
Java Base64加密.解密原理Java代码 转自:http://blog.csdn.net/songylwq/article/details/7578905 Base64是什么: Base64是 ...
- Java Base64加密、解密原理Java代码(转载)
博客来源:http://blog.csdn.net/songylwq/article/details/7578905 Base64是什么: Base64是网络上最常见的用于传输8Bit字节代码的编码方 ...
- 像写C#一样编写java代码
JDK8提供了非常多的便捷用法和语法糖,其编码效率几乎接近于C#开发,maven则是java目前为止最赞的jar包管理和build工具,这两部分内容都不算多,就合并到一起了. 愿编写java代码的过程 ...
- JAVA代码实现嵌套层级列表,POI导出嵌套层级列表
要实现POI导出EXCEL形如 --A1(LV1) ----B1(LV2) ----B2(LV2) ------C1(LV3) ------C2(LV3) ----B3(LV2) --A1(LV1)
- mongodb3.0分片及java代码连接操作测试(开启用户验证)
最近抽时间搭建了一下mongodb简单的分片,整个过程还算是蛮顺利,只不过在用户验证这一块遇到了一些问题,好在最后终于搞定. 一.服务器搭建过程: 1.安装四个mongodb:一个作为config.一 ...
- MQTT研究之EMQ:【JAVA代码构建X509证书【续集】】
openssl创建私钥,获取公钥,创建证书都是比较简单的,就几个指令,很快就可以搞定,之所以说简单,是因为证书里面的基本参数配置不需要我们组装,只需要将命令行里面需要的几个参数配置进去即可.但是呢,用 ...
- MQTT研究之EMQ:【JAVA代码构建X509证书】
这篇帖子,不会过多解释X509证书的基础理论知识,也不会介绍太多SSL/TLS的基本信息,重点介绍如何用java实现SSL协议需要的X509规范的证书. 之前的博文,介绍过用openssl创建证书,并 ...
- Java代码实现文件添加数字签名、验证数字签名
Linux下实现加签.验签 1.使用OpenSSL 生成公钥和密钥: #用 OpenSSL, Linux 上自带,常用命令如下: #生成 RSA 私钥(传统格式的) openssl genrsa -o ...
- [工具] 将Sublime Text 3配置为Java代码编辑器
新建编译器选项 选择菜单栏中的 Tools ——> Build System ——> New Build System ,输入: { "cmd": ["jav ...
随机推荐
- Android ContentProvider和getContentResolver
安卓系统中的数据库SqlLite操作和java中mysql的数据库操作很不一样,造成这样的原因是因为在安卓中数据库是属于进程的不存在数据库客户端,也不存在数据库服务器. 关于SqlLite数据库的文章 ...
- android视频播放
视频播放我们用到的是MediaPlayer,显示控件使用的surfaceView 我们向SD卡中先添加个视频文件,我的是xajh.3gp,不要用mp4,MP4会出现 should have subti ...
- applicationDefaultJvmArgs:
server.context-path=/HelloMultiServlet server.port=8080 applicationDefaultJvmArgs: [ "-agentlib ...
- 解读30个提高Web程序执行效率的好经验
其实微博是个好东西,关注一些技术博主之后,你不用再逛好多论坛了,因为一些很好的文章微博会告诉你,最近看到酷勤网推荐的一篇文章<30个提高Web程序执行效率的好经验>,文章写得不错,提到一些 ...
- 将eclipse新建项目的默认编码GBK改为UTF-8
在eclipse下: 新建项目默认编码设置:Window->Preferences->General->Workspace->Text file encoding 将其改为UF ...
- Asp.net--Ajax前后台数据交互
转自:http://www.cnblogs.com/guolebin7/archive/2011/02/22/1961737.html 代码由前后台两部分组成: 前台:(新建一个Default.asp ...
- Devexpress 汉化 代码 zt
将一下代码放到需要汉化的窗体Load事件中 解压汉化初丁文件 /// <summary> /// 汉化DX控件 /// </summary> private void Chin ...
- Entity Framework快速入门笔记—增删改查
第一步:创建一个控制台应用程序,起名为EFDemo 2. 第二步:创建一个实体模型 (1)在EFDemo项目上面右击选择添加—新建项—在已安装的选项中选择数据—ADO.NET实体对象模型,如图所示: ...
- c语音中打印参数调用层级即call stack, call trace
http://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c There's backtrace(), a ...
- spark高级排序彻底解秘
排序,真的非常重要! RDD.scala(源码) 在其,没有罗列排序,不是说它不重要! 1.基础排序算法实战 2.二次排序算法实战 3.更高级别排序算法 4.排序算法内幕解密 1.基础排序算法实战 启 ...