C# base64URL编码

本文介绍Base64及Base64URL编码原理,并提供Java与C#两种语言实现的时间戳编码成6位字符串的算法示例。通过左移运算和模运算两种方式展示如何将时间戳转换为特定格式的字符串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C#中有对应的Base64处理函数:例如把byte[] 转成base64字符串Convert.ToBase64String

base64是用64个字符来表示任意二进制数据的方法,它对二进制数据进行处理,它把每6bit前缀补0转成8bit后,再查base64字符表得到转化后的结果。

base64编码所用的64个字符为:A-Za-z0-9+/

base64URL编码基于base64编码,把字符+和/分别变成-和_。

同理:还有base58, base58去掉了0(数字0)、O (大写字母O)、 I (大写的字母i) and l (小写的字母L) 、/、 +等。

在java8中有对应的处理函数:Base64.getUrlEncoder().encodeToString

C#中没有找到对应的处理函数,基于以上理解可以直接做字符替换:

    string temp = Convert.ToBase64String(dataBytes);
    string basedTimeStr = temp.Replace("+", "-").Replace("/", "_");

应用实例:unix时间戳的编码成6位字符串的算法:

java代码为:

public class Base64URLEncoder {
 
       public static String encode(long ts) {
             return Base64.getUrlEncoder().encodeToString(ByteBuffer.allocate(Long.BYTES).putLong((ts / 1000) << 28).array())
                          .substring(0, 6);
       }

C#代码为:

 /// <summary>
        /// 时间编码
        /// </summary>
        /// <param name="dtNow">当前本地时间</param>
        /// <returns></returns>
        string GetDate(DateTime dtNow)
        {
            DateTime dtStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            TimeSpan span = dtNow.ToUniversalTime() - dtStart;
            long currentTimeSeconds= (long)(span.TotalSeconds) << 28;
            var dataBytes = BitConverter.GetBytes(currentTimeSeconds);
            Array.Reverse(dataBytes);
            string temp = Convert.ToBase64String(dataBytes);
            string basedTimeStr = temp.Replace("+", "-").Replace("/", "_"); ;
            string result = basedTimeStr.Substring(0, 6);//只返回前6位
            return result;
        }

        /// <summary>
        /// 时间解码
        /// </summary>
        /// <param name="code"></param>
        /// <returns>返回本地时间</returns>
        DateTime DeCodeDate(string code)
        {
            byte[] bytes = Convert.FromBase64String(code);
            Array.Reverse(bytes);
            ulong tt = BitConverter.ToUInt64(bytes, 0);
            DateTime dtStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            //DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1, 0, 0, 0, 0));
            long unixTime = (long)tt >> 28;
            return dtStart.AddSeconds(unixTime).ToLocalTime();
        }

对应的另外一种算法2,对64取模:

        string s_base64url = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
        string GetDate2(DateTime dtNow)
        {
            DateTime dtStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            TimeSpan span = dtNow.ToUniversalTime() - dtStart;
            long sek =(long) Math.Floor(span.TotalSeconds);
            StringBuilder stringBuilder = new StringBuilder();
            while (sek > 0)
            {
                long n = sek % 64;
                char baseStr = s_base64url[(int)n];
                stringBuilder.Insert(0,baseStr);
                sek = (long)Math.Floor((double)sek/64);
            }
            return stringBuilder.ToString().PadLeft(6,'A');
        }

 算法2的计算过程同base58的方式,之所以计算1和计算2结果相同,是因为本质都是64进制。

对算法1中左移28位(<<28)的理解:

因为base64是每6bit一个转码,如果需求是把时间戳转成6位字符,则时间戳从低位开始的6*6=36有效,剩下64-36=28位都是0,其他位都是1,则最大可表示的年月日为:4147/8/20 15:32:15

  string longBinaryStr = "00000000 00000000 00000000 00001111 11111111 11111111 11111111 11111111".Replace(" ","");
            long unixTime = Convert.ToInt64(longBinaryStr, 2);
            DateTime dt = dtStart.AddSeconds(unixTime).ToLocalTime();

 <<28

基于上面的理解:写一个解码函数:

 private void DecodeBase64URLString(string code)
        {    
            string s_base64url = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";        
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 6; i++)
            {
                byte ch_index = (byte)s_base64url.IndexOf(code[i]);
                string tempBinary = Convert.ToString(ch_index, 2).PadLeft(6,'0');
                sb.Append(tempBinary);
            }
            for (int i = sb.Length; i < 64; i++)
            {
                sb.Append("0");
            }
            long unix = Convert.ToInt64(sb.ToString(), 2);
            DateTime dtStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            long test = (long)unix >> 28;
            DateTime dtR= dtStart.AddSeconds(test).ToLocalTime();
            this.txtDate.Text = dtR.ToString("yyyy-MM-dd HH:mm:ss");
        }

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值