Base64编码原理与实现

本文为原创,如需转载,请注明作者和出处,谢谢!

    Base64编码的原理是按bit将每6个bit转换成Base64编码表中的相应字符。下面是Base64的编码表:

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
15 P 32 g 49 x
16 Q 33 h 50 y

    在转换到最后一个字节时,可能出现如下两种情况:
    1.  最后只剩下2个bit。
    2.  最后只剩下4个bit。
    对于这两种情况,需要在后面被0,如下面的两个字节:
   
    11011001   11011101

    在转换上面的字节时,最后会剩下4个bit。也就是1101,这时需要在后面补0,也就是变成了110100。如果后面补一对0,转换结果后面加一个“=”,如果补两对0,加两个“=”,也就是总共的bit数除3的余数为1,则加一个“=”,余数为2,加两个“=”。上面的两个字节是16个bit,除3的余数是1,因此,需要补一个“=”,也就是将这两个字节分成如下三组:
   
    110110    011101    110100  

    其中110100后面两个0是补的,因此,查找上面的base64编码表可将这两个字节转换成如下的Base64编码:

    2d0 =

    下面我们来实现这个算法。算法的基本原理如下:

    由于每次转换都需要6个bit,而这6个bit可能都来自一个字节,也可以来自前后相临的两个字节。定义两个变量:prevByteBitCount和nextByteBitCount,这两个变量分别表述从前一个和后一个节字取得的bit数。如果prevByteBitCount为0,表示6个bit全部来自下一个字节的高6位。如果nextByteBitCount = 0,表示6个bit全部来自前一个字节的低6位。最后通过适当的移位获得所需要的6个bit,再在上面的base64编码表中查找相应的字符。算法的实现代码如下:

     public   static  String encoder( byte [] bytes)
    {
        StringBuilder result 
=   new  StringBuilder();
        String base64 
=   " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ " ;
        
//   prevByteBitCount表示从前一个字节取得的bit数,nextByteBitCount表示从后一个字节取得的bit数
         int  prevByteBitCount  =   0 , nextByteBitCount  =   6 ;
        
//   i表示当前的数组索引,n表示已经处理的位数
         int  i  =   0 , n  =   0 ;
        
//   byteCount表示总的位数
         int  byteCount  =   8   *  bytes.length;
        
byte  b  =   0 ;
        
while  ( true )
        {
            
//   处理从前后两个字节取得位数的情况
             if  (prevByteBitCount  >   0   &&  nextByteBitCount  >   0 )
            {
                
//  将前一个字节的低位向左移nextByteBitCount个bit,并使下一个字节的高位(nextByteBitCount指定的位数)右移到字节的最低位,
                
//  然后将两个位移结果进行逻辑或,也就是将从前一个字节和后一个字节取得的相应的bit合并为一个字节的低位
                b  =  ( byte ) ((( 0xff   &  bytes[i])  <<  nextByteBitCount)  |  (( 0xff   &  bytes[i  +   1 ])  >>  ( 8   -  nextByteBitCount)));
                
//   将逻辑或后的结果的最高两个bit置成0
                b  =  ( byte ) (b  &   0x3f );
                prevByteBitCount 
=   8   -  nextByteBitCount;
                nextByteBitCount 
=   6   -  prevByteBitCount;
            }
            
//   处理从后一个字节取得高6位的情况
             else   if  (prevByteBitCount  ==   0 )
            {
                
//   后一个字节的高6位右移动低6位
                b  =  ( byte ) (( 0xff   &  bytes[i])  >>  ( 8   -  nextByteBitCount));
                
//   处理后面的位时,就是从前一个字节取2个bit,从后一个字字取4个bit
                prevByteBitCount  =   2 ;
                nextByteBitCount 
=   4 ;

            }
            
//   处理从前一个字节取得低6位的情况
             else   if  (nextByteBitCount  ==   0 )
            {
                
//   将前一个字节的最高两个bit置成0
                b  =  ( byte ) ( 0x3f   &  bytes[i]);
                
//   处理后面的位时,从后一个字节取6个bit
                prevByteBitCount  =   0 ;
                nextByteBitCount 
=   6 ;

            }
            result.append(base64.charAt(b));
            n 
+=   6 ;
            i 
=  n  /   8 ;
            
int  remainBitCount  =  byteCount  -  n;
            
if  (remainBitCount  <   6 )
            {
                
//   将剩余的bit补0后,仍然需要在base64编码表中查找相应的字符,并添加到结果字符串的最后
                 if  (remainBitCount  >   0 )
                {
                    b 
=  bytes[bytes.length  -   1 ];
                    b 
=  ( byte ) ( 0x3f   &  (b  <<  ( 6   -  remainBitCount)));
                    result.append(base64.charAt(b));
                }
                
break ;
            }
        }
        
//   如果总bit数除3的余数为1,加一个“=”,为2,加两个“=”
        n  =  byteCount  %   3 ;
        
for  (i  =   0 ; i  <  n; i ++ )
            result.append(
" = " );

        
return  result.toString();
    }
 
    最后可以使用下面的代码来验证encoder方法的正确性:

    String s  =   " 中华人民共和国 " ;
   
byte [] bytes  =  s.getBytes( " UTF-8 " );
    System.out.println(encoder(bytes));
   
//   使用jdk提供的base64转换类对字节数组进行base64编码
    sun.misc.BASE64Encoder base64Encoder  =   new  sun.misc.BASE64Encoder();
    System.out.println(base64Encoder.encode(bytes));

    上面的代码的执行结果如下:

5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9
5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9


国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

你可能感兴趣的:(Base64编码原理与实现)