Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 450|回复: 0

[算法学习]用Base64编码与解码

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-8 00:05:03 | 显示全部楼层 |阅读模式
    Base64是网络上最常见的用于加密传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。

           Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。

    这样说会不会太抽象了?不怕,我们来看一个例子:
       
         
          
          转换前
          aaaaaabb
          ccccdddd
          eeffffff
          
          
          
          转换后
          00aaaaaa
          00bbcccc
          00ddddee
          00ffffff
          
         
       
         应该很清楚了吧?上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。

      
       
       
       

       
      
         转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:(摘自RFC2045)


                                 Table 1: The Base64 Alphabet

           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


    让我们再来看一个实际的例子,加深印象!

      

      
       
       转换前
       10101101
       10111010
       01110110
       
       
       
       转换后
       00101011
       00011011
       00101001
       00110110
       
       
       十进制
       43
       27
       41
       54
       
       
       对应码表中的值
       r
       b
       p
       2
       
      
    所以上面的24位编码,编码后的Base64值为 rbp2
    解码同理,把 rbq2 的二进制位连接上再重组得到三个8位值,得出原码。
    (解码只是编码的逆过程,在此我就不多说了,另外有关MIME的RFC还是有很多的,如果需要详细情况请自行查找。) 下面的Base64编码/解码程序来自网上。 一、用SUN的API解码和编码
    1. import java.io.*;
    2. import sun.misc.BASE64Decoder;
    3. import sun.misc.BASE64Encoder;
    4. public class Base64
    5. {
    6.   public static void main(String[] args) {
    7.     if (args.length == 2) {
    8.       String string = Base64.encode(args[0]);
    9.       Base64.decode(string, args[1]);
    10.     } else
    11.       System.out.println("usage: java Base64 inputFile outputFile");
    12.   }
    13.   public static String encode(String fileName) {
    14.     String string = null;
    15.     try {
    16.       InputStream in = new FileInputStream(fileName);
    17.       // in.available()返回文件的字节长度
    18.       byte[] bytes = new byte[in.available()];
    19.       // 将文件中的内容读入到数组中
    20.       in.read(bytes);
    21.       string = new BASE64Encoder().encode(bytes);
    22.       in.close();
    23.     } catch (FileNotFoundException fe) {
    24.       fe.printStackTrace();
    25.     } catch(IOException ioe) {
    26.       ioe.printStackTrace();
    27.     }
    28.     return string;
    29.   }
    30.   public static void decode(String string, String fileName) {
    31.     try {
    32.       // 解码,然后将字节转换为文件
    33.       byte[] bytes = new BASE64Decoder().decodeBuffer(string);
    34.       ByteArrayInputStream in = new ByteArrayInputStream(bytes);
    35.       byte[] buffer = new byte[1024];
    36.       FileOutputStream out = new FileOutputStream(fileName);
    37.       int bytesum = 0;
    38.       int byteread = 0;
    39.       while ((byteread = in.read(buffer)) != -1) {
    40.         bytesum += byteread;
    41.         out.write(buffer, 0, byteread);
    42.       }
    43.     } catch(IOException ioe) {
    44.       ioe.printStackTrace();
    45.     }
    46.   }
    47. }
    复制代码
    二、

    1. /* @author CuCuChen
    2. * @version $Id$
    3. */
    4. import java.io.*;
    5. class Base64Helper {

    6. //从文本文件对象中读取内容并转换为字符数组
    7. public static char[] readChars(File file)
    8. {
    9.      CharArrayWriter caw = new CharArrayWriter();
    10.      try
    11.      {
    12.          Reader fr = new FileReader(file);
    13.         Reader in = new BufferedReader(fr);
    14.          int count = 0;
    15.          char[] buf = new char[16384];
    16.         while ((count=in.read(buf)) != -1) {
    17.              if (count > 0) caw.write(buf, 0, count);
    18.          }
    19.          in.close();
    20.      }
    21.      catch (Exception e) { e.printStackTrace(); }
    22.      return caw.toCharArray();
    23. }

    24. //从字符串对象中读取内容并转换为字符数组
    25. public static char[] readChars(String string)
    26. {
    27.      CharArrayWriter caw = new CharArrayWriter();
    28.      try
    29.      {
    30.          Reader sr = new StringReader(string.trim());
    31.         Reader in = new BufferedReader(sr);
    32.          int count = 0;
    33.          char[] buf = new char[16384];
    34.         while ((count=in.read(buf)) != -1) {
    35.              if (count > 0) caw.write(buf, 0, count);
    36.          }
    37.          in.close();
    38.      }
    39.      catch (Exception e) { e.printStackTrace(); }
    40.      return caw.toCharArray();
    41. }

    42. //从二进制文件对象中读取内容并转换为字节数组
    43. public static byte[] readBytes(File file)
    44. {
    45.      ByteArrayOutputStream baos = new ByteArrayOutputStream();
    46.      try
    47.      {
    48.          InputStream fis = new FileInputStream(file);
    49.          InputStream is = new BufferedInputStream(fis);
    50.         int count = 0;
    51.          byte[] buf = new byte[16384];
    52.          while ((count=is.read(buf)) != -1) {
    53.              if (count > 0) baos.write(buf, 0, count);
    54.          }
    55.          is.close();
    56.     }
    57.      catch (Exception e) { e.printStackTrace(); }
    58.      return baos.toByteArray();
    59. }

    60. //写字节数组内容到二进制文件
    61. public static void writeBytes(File file, byte[] data) {
    62.      try {
    63.          OutputStream fos = new FileOutputStream(file);
    64.          OutputStream os = new BufferedOutputStream(fos);
    65.          os.write(data);
    66.          os.close();
    67.      }
    68.      catch (Exception e) { e.printStackTrace(); }
    69. }
    70. //写字符数组内容到文本文件
    71. public static void writeChars(File file, char[] data) {
    72.      try {
    73.          Writer fos = new FileWriter(file);
    74.          Writer os = new BufferedWriter(fos);
    75.         os.write(data);
    76.          os.close();
    77.      }
    78.      catch (Exception e) { e.printStackTrace(); }
    79. }
    80. }

    81. public class Base64{
    82. //编码文件对象所指的文件
    83. static public char[] encode(File file){
    84.   if (!file.exists()) {
    85.   System.err.println("错误:文件不存在!");
    86.   return null;
    87.   }
    88. return encode(Base64Helper.readBytes(file));
    89. }

    90. //编码文件名所指的文件
    91. static public char[] encode(String filename){
    92. File file = new File(filename);
    93.   if (!file.exists()) {
    94.   System.err.println("错误:文件“"+filename+"”不存在!");
    95.   return null;
    96.   }
    97. return encode(Base64Helper.readBytes(file));
    98. }
    99. //编码传入的字节数组,输出编码后的字符数组
    100. static public char[] encode(byte[] data)
    101. {
    102.   char[] out = new char[((data.length + 2) / 3) * 4];
    103. //
    104.   // 对字节进行Base64编码,每三个字节转化为4个字符.
    105.   // 输出总是能被4整除的偶数个字符
    106.   //
    107.   for (int i=0, index=0; i< data.length; i+=3, index+=4) {
    108.   boolean quad = false;
    109.   boolean trip = false;
    110.   int val = (0xFF & (int) data[i]);
    111.   val <<= 8;
    112.   if ((i+1) < data.length) {
    113.   val |= (0xFF & (int) data[i+1]);
    114.   trip = true;
    115.   }
    116.   val <<= 8;
    117.   if ((i+2) < data.length) {
    118.   val |= (0xFF & (int) data[i+2]);
    119.   quad = true;
    120.   }
    121.   out[index+3] = alphabet[(quad? (val & 0x3F): 64)];
    122.   val >>= 6;
    123.   out[index+2] = alphabet[(trip? (val & 0x3F): 64)];
    124.   val >>= 6;
    125.   out[index+1] = alphabet[val & 0x3F];
    126.   val >>= 6;
    127.   out[index+0] = alphabet[val & 0x3F];
    128.   }
    129.     return out;
    130. }
    131. static public byte[] decode(char[] data)
    132. {
    133.   // 程序中有判断如果有回车、空格等非法字符,则要去掉这些字符
    134.   // 这样就不会计算错误输出的内容
    135.   int tempLen = data.length;
    136.   for( int ix=0; ix< data.length; ix++ )
    137.   {
    138.   if( (data[ix] > 255) || codes[ data[ix] ] < 0 )
    139.   --tempLen; // 去除无效的字符
    140.   }
    141.   // 计算byte的长度
    142.   // -- 每四个有效字符输出三个字节的内容
    143.   // -- 如果有额外的3个字符,则还要加上2个字节,
    144.   // 或者如果有额外的2个字符,则要加上1个字节
    145.   int len = (tempLen / 4) * 3;
    146.   if ((tempLen % 4) == 3) len += 2;
    147.   if ((tempLen % 4) == 2) len += 1;
    148.   byte[] out = new byte[len];
    149.   int shift = 0;
    150.   int accum = 0;
    151.   int index = 0;
    152.   // 一个一个字符地解码(注意用的不是tempLen的值进行循环)
    153.   for (int ix=0; ix< data.length; ix++)
    154.   {
    155.   int value = (data[ix]>255)? -1: codes[ data[ix] ];
    156.   if ( value >= 0 ) // 忽略无效字符
    157.   {
    158.   accum <<= 6;
    159.   shift += 6;
    160.   accum |= value;
    161.   if ( shift >= 8 )
    162.   {
    163.   shift -= 8;
    164.   out[index++] =
    165.   (byte) ((accum >> shift) & 0xff);
    166.   }
    167.   }
    168.   }
    169.   //如果数组长度和实际长度不符合,那么抛出错误
    170.   if( index != out.length)
    171.   {
    172.   throw new Error("数据长度不一致(实际写入了 " + index + "字节,但是系统指示有" + out.length + "字节)");
    173.   }
    174.   return out;
    175. }
    176. //
    177. // 用于编码的字符
    178. //
    179. static private char[] alphabet ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
    180. //
    181. // 用于解码的字节(0-255)
    182. //
    183. static private byte[] codes = new byte[256];
    184. static {
    185.   for (int i=0; i<256; i++) codes[i] = -1;
    186.   for (int i = "A"; i <= "Z"; i++) codes[i] = (byte)( i - "A");
    187.   for (int i = "a"; i <= "z"; i++) codes[i] = (byte)(26 + i - "a");
    188.   for (int i = "0"; i <= "9"; i++) codes[i] = (byte)(52 + i - "0");
    189.   codes["+"] = 62;
    190.   codes["/"] = 63;
    191. }
    192. public static void main (String [] args){
    193.   String key = new String("Spider");
    194.   byte[] a = key.getBytes();
    195.   char[] b = Base64.encode(a) ;
    196.   System.out.println(new String(b));
    197.    //for(int i=0;i< b.length;i++){
    198.    //  System.out.println(b[i]);
    199.    //}
    200.   byte[] c = Base64. decode(b);
    201.   System.out.println(new String(c));
    202. }
    203. }  
    204. 运行结果:
    205. C:java>java Base64
    206. U3BpZGVy
    207. Spider
    复制代码


      
      
       
       

         
       

         
       
      



    源码下载:http://file.javaxxz.com/2014/11/8/000503375.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 10:34 , Processed in 0.331156 second(s), 34 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表