防君子,不防小人--咱也谈谈Base64编码


Posted on December 11, 2008


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还是有很多的,如果需要详细情况请自行查找。)

用更接近于编程的思维来说,编码的过程是这样的:

第一个字符通过右移2位获得第一个目标字符的Base64表位置,根据这个数值取到表上相应的字符,就是第一个目标字符。
然后将第一个字符左移4位加上第二个字符右移4位,即获得第二个目标字符。
再将第二个字符左移2位加上第三个字符右移6位,获得第三个目标字符。
最后取第三个字符的右6位即获得第四个目标字符。

在以上的每一个步骤之后,再把结果与 0x3F 进行 AND 位操作,就可以得到编码后的字符了。

Base64将3个字节转变为4个字节,因此,编码后的代码量(以字节为单位,下同)约比编码前的代码量多了1/3。之所以说是“约”,是因为如果代码量正好是3的整数倍,那么自然是多了1/3。但如果不是呢?
细心的人可能已经注意到了,在The Base64 Alphabet中的最后一个有一个(pad) =字符。这个字符的目的就是用来处理这个问题的。
当代码量不是3的整数倍时,代码量/3的余数自然就是2或者1。转换的时候,结果不够6位的用0来补上相应的位置,之后再在6位的前面补两个0。转换完空出的结果就用就用“=”来补位。

不错的编码,其实研究这个编码的目的,也是想处理HTML的时候,比如操作数据库的时候,不用考试单引号之类的符号了,最后附上C#编码转换的程序:

    class Program
    {
        static void Main(string[] args)
        {
            //string s = "´´´";
            string s = "中文";
            byte[] bt = System.Text.Encoding.UTF8.GetBytes(s);
            string s64 = Convert.ToBase64String(bt);
            Console.WriteLine("s = " + s + " " + s.Length);
            Console.WriteLine("s64 = " + s64 + " " + s64.Length);
            byte[] btFrom64 = Convert.FromBase64String(s64);
            //byte[] btTo64 = Convert.FromBase64String(s64);
            string news = Encoding.GetEncoding("UTF-8").GetString(btFrom64);
            Console.WriteLine("news = " + news + " " + news.Length);
        }
    }


标签:N/A

 

在线学习答案查询入口
微信扫码联系
微信扫码联系