Base64编码介绍及基于Java语言实现

简介: Base64编码介绍及基于Java语言实现

Base64编码介绍及基于Java语言实现



Base64编码被设计用来表示任意顺序的八位一个字节单元,允许使用大写和小写字符而不要求内容可读。65个US-ASCII子集被用来表示Base64编码,所以每六位表示一个可以打印的Base64的字符,第65字符’=’被用来表示特殊处理的功能字符,后面会详细说明。



预编码处理一次输入24位(三个字符)作为一组,输出的是四个Base64的编码字符24位(每个字符六位)。编码处理遵循从左到右的顺序,一个24位的输入可以看作是三个八位的字符组,


编码以后,24位的字符则被转换为四个6位的字符组,每个字符被翻译成Base64字符表中的匹配的一个字符。



每六位都被转换成为一个index数值去匹配Base64编码表中的一个字符输出,Base64的字符表如下:



Value Encoding Value Encoding Value Encoding Value Encoding


0 A                  17 R              34 i      51 z


1 B                  18 S              35 j       52 0


2 C                  19 T              36 k      53 1


3 D                  20 U              37 l       54 2


4 E                  21 V              38 m       55 3


5 F                  22 W              39 n       56 4


6 G                  23 X              40 o       57 5


7 H                  24 Y              41 p       58 6


8 I                  25 Z              42 q       59 7


9 J                  26 a              43 r       60 8


10 K                 27 b              44 s       61 9


11 L                 28 c              45 t       62 +


12 M                 29 d              46 u       63 /


13 N                 30 e              47 v


14 O                 31 f              48 w       (pad) =


15 P                  32 g             49 x


16 Q                 33 h              50 y





字符’=’作为填充字符,对于任何不满足24为输入的编码字符,以零做作为填充成为24位(三字节)输入,对于任何输出的编码字符小于24位的都应当以’=’字符填充。对于以下情形:



Ø        最后输入正好是24位的编码字符,则不需要’=’字符填充,输出即为四个Base64字符编码.


Ø        最后输入只有八位的编码字符,则需要填充两个特殊字符’=’,输出即为两个Base64字符编码加上两个’=’.


Ø        最后输入只有十六位的编码字符,则需要填充一个特殊字符’=’,输出即为三个Base64字符加上一个’=’.


 


把一个二进制的数据转换为Base64的编码,下面的例子就说明Base64怎么编码三个字节的二进制数据的。


+--first octet--+-second octet--+--third octet--+


|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|


+-----------+---+-------+-------+---+-----------+


|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|


+--1.index--+--2.index--+--3.index--+--4.index--+



许多网络程序中用来传输二进制文件也经常采用Base64的编码算法,一个最典型的例子就是Email的应用协议SMPT发送MIME数据的时候就常采用Base64来发送,而且已经被写入标准的RFC中,在Java语言中,JDK已经提供了Base64的API。



下面基于Java实现的Base64的编码和解码程序,相比于JDK6中把Base64编码和解码分在两个不同的API Class中,因此还把许多人搞得很晕来说,也许本人的实现会略微方便点。

package com.gloomyfish.smtp.util;
 
 
public class Base64Coder {
  
  public final static char[] base64_alphabet = new char[]{
            'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S'
            ,'T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l'
            ,'m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4'
            ,'5','6','7','8','9','+','/','='
  };
  
  public static String encode(String content) {
    
    byte[] data = content.getBytes();
    int length = data.length;
    byte[] char_array_3 = new byte[]{0, 0, 0};
    byte[] char_array_4 = new byte[]{'=','=','=','='};
    String retContent = "";
    int i = 0;
    int j = 0;
    int reversePos = 0;
    while(length > 0) {
      length--;
      char_array_3[i++] = data[reversePos++];
      if(i==3) {
        char_array_4[0] = (byte)((char_array_3[0] & 0xfc) >> 2); // convert the char
          char_array_4[1] = (byte)(((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4));
          char_array_4[2] = (byte)(((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6));
          char_array_4[3] = (byte)(char_array_3[2] & 0x3f);
          for(i = 0; (i <4) ; i++)
            retContent += base64_alphabet[char_array_4[i]];
          i = 0;
      }
    }
    
    // handling the last input content
      if (i > 0 )
      {
        for(j = i; j < 3; j++)
          char_array_3[j] = 0; // padding of zero
 
        char_array_4[0] = (byte)((char_array_3[0] & 0xfc) >> 2); // right shift
        char_array_4[1] = (byte)(((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4));
        char_array_4[2] = (byte)(((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6));
        char_array_4[3] = (byte)(char_array_3[2] & 0x3f);
 
        for (j = 0; (j < i + 1); j++)
          retContent += base64_alphabet[char_array_4[j]];
 
        while((i++ < 3)) // padding of '=' of output string
          retContent += '=';
 
      }
    return retContent;
  }
  
  public static String decode(String enContent) {
    byte[] data = enContent.getBytes();
    int i = 0, j = 0, enCode = 0;
    int mLength = data.length;
    byte[] char_array_4 = new byte[4];
    byte[] char_array_3 = new byte[3];
    String retContent = "";
 
    // filter out the padding '=' chars
      while (mLength > 0 && (((char)data[enCode]) != '=') && isBase64((char)data[enCode])) 
      {
        mLength--;
        char_array_4[i++] = data[enCode++];
        if (i ==4) {
          for (i = 0; i <4; i++)
            char_array_4[i] = findChar((char)char_array_4[i]);
 
          char_array_3[0] = (byte)((char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4));
          char_array_3[1] = (byte)(((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2));
          char_array_3[2] = (byte)(((char_array_4[2] & 0x3) << 6) + char_array_4[3]);
 
          for (i = 0; (i < 3); i++)
            retContent += (char)char_array_3[i];
          i = 0;
        }
      }
 
      // last content handling
      if (i > 0) 
      {
        for (j = i; j <4; j++)
          char_array_4[j] = 0;
 
        for (j = 0; j <4; j++)
          char_array_4[j] = findChar((char)char_array_4[j]);
 
        char_array_3[0] = (byte)((char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4));
        char_array_3[1] = (byte)(((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2));
        char_array_3[2] = (byte)(((char_array_4[2] & 0x3) << 6) + char_array_4[3]);
 
        for (j = 0; (j < i - 1); j++) 
          retContent += (char)char_array_3[j];
      }
 
      return retContent;
  }
  
  public static boolean isBase64(char c) 
  {
    boolean base64 = false;
    for(int i=0; i<64; i++) {
      if( c == base64_alphabet[i]) {
        base64 = true;
        break;
      }
    }
    return base64;
  }
  
  public static byte findChar(char x) {
    byte index = 64; // 65th char '='
    for(int i=0; i<64; i++) {
      if( x == base64_alphabet[i]) {
        index = (byte)i;
        break;
      }
    }
    return index;
  }
  
  /**
   * <p> test data and result should like below output , RFC4648 Sample </p>
   *  BASE64("") = ""
   *  BASE64("f") = "Zg=="
   *  BASE64("fo") = "Zm8="
   *  BASE64("foo") = "Zm9v"
   *  BASE64("foob") = "Zm9vYg=="
   *  BASE64("fooba") = "Zm9vYmE="
   *  BASE64("foobar") = "Zm9vYmFy"
   *
   *
   * @param args
   */
  public static void main(String[] args) {
    // BASE64Encoder coder = new BASE64Encoder();
    // System.out.println(coder.encode("foobar".getBytes()));
    
    System.out.println("#--------------encode---------------#");
    System.out.println(encode(""));
    System.out.println(encode("f"));
    System.out.println(encode("fo"));
    System.out.println(encode("foo"));
    System.out.println(encode("foob"));
    System.out.println(encode("fooba"));
    System.out.println(encode("foobar"));
    System.out.println(encode("123456789sS{1}quot;));
    System.out.println("#--------------decode---------------#");
    System.out.println(decode(""));
    System.out.println(decode("Zg=="));
    System.out.println(decode("Zm8="));
    System.out.println(decode("Zm9v"));
    System.out.println(decode("Zm9vYg=="));
    System.out.println(decode("Zm9vYmE="));
    System.out.println(decode("Zm9vYmFy"));
    System.out.println(decode("MTIzNDU2Nzg5c1Mk"));
    
  }
}
相关文章
|
4天前
|
数据可视化 Java
Java语言使用DL4J实现图片分类
【6月更文挑战第14天】Java语言使用DL4J实现图片分类
14 3
|
5天前
|
JavaScript Java Android开发
在cmd中运行javac编译java文件报错: 编码GBK的不可映射字符、 非法字符: \65279
在cmd中运行javac编译java文件报错: 编码GBK的不可映射字符、 非法字符: \65279
13 1
|
1天前
|
算法 Java 应用服务中间件
【Java】提高千倍效率的35个编码小技巧
【Java】提高千倍效率的35个编码小技巧
9 4
|
1天前
|
Java 程序员 API
Java中的函数式编程:一种现代化的编码实践
在Java的世界中,面向对象编程(OOP)长期占据着主导地位。然而,随着软件工程的不断进步和编程语言的发展,函数式编程(FP)作为一种更加简洁、表达力更强的编程范式,逐渐在Java社区中获得了认可。本文将深入探讨Java如何拥抱函数式编程的概念,包括Lambda表达式、Stream API等特性的介绍,以及它们如何改变了我们编写和维护代码的方式。通过实际示例,我们将揭示函数式编程如何在提高代码可读性、简化并行处理等方面展现其优势,同时也指出了在学习和应用这一范式时可能遇到的挑战与解决策略。
|
3天前
|
Java Apache
Java将一个对象的属性复制到另一个对象,如何编码
【6月更文挑战第15天】Java将一个对象的属性复制到另一个对象,如何编码
10 3
|
4天前
|
IDE Oracle Java
[笔记] 疯狂JAVA讲义(第3版) 第1章 Java语言概述与开发环境
[笔记] 疯狂JAVA讲义(第3版) 第1章 Java语言概述与开发环境
|
5天前
|
Java
Unicode编码和中文互转(JAVA实现)
Unicode编码和中文互转(JAVA实现)
8 1
|
存储 Java 编译器
Java语言------图书馆管理系统(入门简略版)
Java语言------图书馆管理系统(入门简略版)
98 0
Java语言------图书馆管理系统(入门简略版)
|
Java
Java学习路线-53:EL(表达式语言)入门及 EL 函数库
Java学习路线-53:EL(表达式语言)入门及 EL 函数库
100 0
|
JavaScript 前端开发 Java
java语言入门总结
java语言入门总结
66 0