博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

base64格式的编码与解码

Posted on 2011-03-14 16:25  李存  阅读(4857)  评论(1)    收藏  举报

一. Base64的编码规则

Base64编码的思想是是采用64个基本的ASCII码字符(并不是ascii码的从1-64码的数据,是从中选出的。)对数据进行重新编码。它将需要编码的数据拆分成字节数组。以3个字节为一组。按顺序排列24 位数据,再把这24位数据分成4组,即每组6位。再在每组的的最高位前补两个0凑足一个字节。这样就把一个3字节为一组的数据重新编码成了4个字节。当所 要编码的数据的字节数不是3的整倍数,也就是说在分组时最后一组不够3个字节。这时在最后一组填充1到2个0字节。并在最后编码完成后在结尾添加1到2个 “=”。

例:将对ABC进行BASE64编码:


1、首先取ABC对应的ASCII码值。A(65)B(66)C(67);
2、再取二进制值A(01000001)B(01000010)C(01000011);
 3、然后把这三个字节的二进制码接起来(010000010100001001000011);
4、 再以6位为单位分成4个数据块,并在最高位填充两个0后形成4个字节的编码后的值,(00
010000)(00010100)(00001001)(00000011),其中蓝色部分为真实数据;
 5、再把这四个字节数据转化成10进制数得(16)(20)(9)(3);
 6、最后根据BASE64给出的64个基本字符表,查出对应的ASCII码字符(Q)(U)(J)(D),这里的值实际就是数据在字符表中的索引。

注:BASE64字符 表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

二.解码 规则

解码过程就是把4个字节再还原成3个字节再根据不同的数据形式把字节数组重新整理 成数据。

三. C#中的实现(2011/03/14)

public class Base64Manager
    {
        /// <summary>
        /// 编码
        /// </summary>
        /// <param name="sStr">要编码的字符串</param>
        /// <returns>编码后的base64格式的字符串</returns>
        public string Encoder(string sStr)
        {
            #region 得到能被3整除的字节数组

            byte[] bs = System.Text.Encoding.UTF8.GetBytes(sStr.ToCharArray());
            if (bs.Length % 3 == 0)
            {
            }
            else if(bs.Length%3==1)
            {
                bs = System.Text.Encoding.UTF8.GetBytes((sStr+"==").ToCharArray());
            }
            else if(bs.Length%3==2)
            {
                bs = System.Text.Encoding.UTF8.GetBytes((sStr+"=").ToCharArray());
            }

            #endregion

            #region 开始base64编码

            byte[] bsLast = new byte[bs.Length / 3 * 4];

            char[] c1;
            char[] c2;
            char[] c3;
            char[] c4 = new char[8] { '0', '0', ' ', ' ', ' ', ' ', ' ', ' ' };
            char[] c5 = new char[8] { '0', '0', ' ', ' ', ' ', ' ', ' ', ' ' };
            char[] c6 = new char[8] { '0', '0', ' ', ' ', ' ', ' ', ' ', ' ' };
            char[] c7 = new char[8] { '0', '0', ' ', ' ', ' ', ' ', ' ', ' ' };
            char[] c8=new char[24];
            for (int i = 0; i < bs.Length; i = i + 3)
            {
                c1 = change(bs[i]);
                c2 = change(bs[i + 1]);
                c3 = change(bs[i + 2]);
                for (int j = 0; j < 8; j++)
                {
                    c8[j] = c1[j];
                    c8[j + 8] = c2[j];
                    c8[j + 16] = c3[j];
                }
                for (int k = 0; k < 6; k++)
                {
                    c4[k + 2] = c8[k];
                    c5[k + 2] = c8[k + 6];
                    c6[k + 2] = c8[k + 12];
                    c7[k + 2] = c8[k + 18];
                }

                bsLast[i / 3 * 4 + 0] = (byte)Change2To10(c4);
                bsLast[i / 3 * 4 + 1] = (byte)Change2To10(c5);
                bsLast[i / 3 * 4 + 2] = (byte)Change2To10(c6);
                bsLast[i / 3 * 4 + 3] = (byte)Change2To10(c7);
            }

            #endregion

            return ChangeToBase64Data(bsLast);
        }

        /// <summary>
        /// 解码
        /// </summary>
        /// <param name="sBase64Data">编码后的base64格式的数据</param>
        /// <returns>解码后的数据</returns>
        public string Decoder(string sBase64Data)
        {
            byte[] b = ChangeToByteData(sBase64Data);
            char[] c = new char[b.Length / 4 * 3 * 8];
            int iState = 0;
            foreach (byte bb in b)
            {
                char[] cc = change(bb);
                for (int i = 0; i < 6; i++)
                {
                    c[iState++] = cc[i + 2];
                }
            }

            byte[] bL = new byte[b.Length / 4 * 3];
            int iStateOther = 0;
            for (int i = 0; i < c.Length / 8; i++)
            {
                char[] cS = new char[8] { ' ',' ',' ',' ',' ',' ',' ',' '};
                for (int j = 0; j < 8; j++)
                {
                    cS[j] = c[i * 8 + j];
                }
                bL[iStateOther++] = (byte)Change2To10(cS);
            }

            #region

            int iCount = 0;
            foreach (byte bbb in bL)
            {
                if (bbb == (byte)0)
                {
                    iCount++;
                }
            }

            byte[] BLL = new byte[bL.Length - iCount];
            for (int i = 0; i < BLL.Length; i++)
            {
                BLL[i] = bL[i];
            }

            #endregion
            return System.Text.Encoding.UTF8.GetString(BLL);
        }

        /// <summary>
        /// 把变换完的字节数组转换为对应的base64表中的数据
        /// </summary>
        /// <param name="byt">要转换的字节数组</param>
        /// <returns>最终的编码之后的数据</returns>
        private string ChangeToBase64Data(byte[] byt)
        {
            char[] sBase64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".ToCharArray();
            string sReturn = "";
            foreach (byte b in byt)
            {
                sReturn += sBase64Table[(Int32)b];
            }
            return sReturn;
        }

        /// <summary>
        /// 编码后的数据转换为字节数组
        /// </summary>
        /// <param name="sBase64Data">经过base64编码的数据</param>
        /// <returns>编码后的字节数组</returns>
        private byte[] ChangeToByteData(string sBase64Data)
        {
            string sBase64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
            char[] cReturn = new char[sBase64Data.Length];
            int iState = 0;
            foreach (char c in sBase64Data)
            {
                cReturn[iState++] = (char)((sBase64Table.IndexOf(c) == -1) ? System.Text.Encoding.UTF8.GetChars(new byte[] { ((byte)0) })[0] : sBase64Table.IndexOf(c));
            }
            return System.Text.Encoding.UTF8.GetBytes(cReturn);
        }

        #region 十进制转二进制 <256的数据

        /// <summary>
        /// 十进制转为二进制数据(传入的数据只能为小于128的整数)
        /// </summary>
        /// <param name="i10">十进制的数据</param>
        /// <returns>转换成的二进制的数组</returns>
        private char[] change(int i10)
        {
            bool state = false;
            char[] ch = new char[] { '0', '0', '0', '0', '0', '0', '0', '0' };
            int iState = 0;
            while (i10 != 0)
            {
                iState++;
                state = false;
                if (i10 % 2 == 1)
                {
                    i10 = i10 / 2;
                    state = true;
                }
                else
                {
                    i10 = i10 / 2;
                }

                if (state)
                {
                    ch[8 - iState] = '1';
                }
                else
                {
                    ch[8 - iState] = '0';
                }
            }

            return ch;
        }

        /// <summary>
        /// 把二进制的八位char数组转为十进制数据
        /// </summary>
        /// <param name="ch">二进制数据</param>
        /// <returns>十进制数</returns>
        private int Change2To10(char[] ch)
        {
            int iReturn = 0;

            for (int i = 0; i < 8; i++)
            {
                if (ch[i] == '1')
                {
                    double d = double.Parse((7 - i).ToString());
                    iReturn += (Int32)System.Math.Pow(2.0, double.Parse((7 - i).ToString()));
                }
            }

            return iReturn;
        }

        #endregion
    }