【问题标题】:An efficient way to Base64 encode a byte array?Base64 编码字节数组的有效方法?
【发布时间】:2012-08-29 12:56:24
【问题描述】:

我有一个byte[],我正在寻找对它进行 base64 编码的最有效方法。

问题在于,内置的.Net 方法Convert.FromBase64CharArray 需要char[] 作为输入,而将我的byte[] 转换为char[] 只是为了再次将其转换为base64 编码数组似乎很愚蠢。

有没有更直接的方法?

[[EDIT:]] 我将解释我想要更好地实现的目标 - 我有一个 byte[],我需要返回一个新的 base64 编码 byte[]

【问题讨论】:

  • 你的字节数组是什么编码的? ascii、utf8 等?
  • 您写的是要转换为 base64 而不是“FromBase64”
  • 也许我遗漏了什么......但你不能使用string Convert.ToBase64String(byte[])byte[] Convert.FromBase64String(string)吗?
  • @SimonWhitehead 我已经更新了我的问题,以澄清为什么这还不够好
  • 将字符串转换为字节是另一回事。使用 byte[] Encoding.ASCII.GetBytes(theBase64String)

标签: c# .net


【解决方案1】:

字节[] -> 字符串: 采用 system.convert.tobase64string

Convert.ToBase64String(byte[] data)

字符串 -> 字节[]: 采用 system.convert.frombase64string

Convert.FromBase64String(string data)

【讨论】:

  • 你能解释一个你需要 base64 byte[] 作为 byte[] 的用例吗?我一生中从未有过这种需要。
  • 将字符串转换为字节是另一回事。使用 Encoding.ASCII.GetBytes(theString)
  • 这就是为什么你总是向下滚动到第二个答案,哈哈。
  • @robnick:这是一个巨大的禁忌。每个得到base64的二进制数据大约是。尺寸增大 33%。所以这不是一个真正有用的用例。尽管如此,你的用例只是被 byte[] -> string.
  • @StephanSchinkel 只要尝试通过ajax请求实现下载pdf或类似格式的文件,你就会遇到这个问题。 :) 例如您没有打开新选项卡或窗口的选项,当前窗口必须不间断并始终保持焦点。我不认为任何类似格式的文件中有 33% 被视为与我们这个时代的带宽的一个非常糟糕的权衡。我不是说它是正确的方法。但有时业务需求需要它,因此它是有效的。
【解决方案2】:

Base64 是一种以文本形式(作为字符串)表示字节的方法。所以不存在 Base64 编码的字节 [] 这样的东西。您将拥有一个 base64 编码的字符串,您可以将其解码byte[]

但是,如果您想要以字节数组结尾,则可以采用 base64 编码的字符串并将其转换为字节数组,例如:

string base64String = Convert.ToBase64String(bytes);
byte[] stringBytes = Encoding.ASCII.GetBytes(base64String);

然而,这没有任何意义,因为将 byte[] 表示为 byte[] 的最佳方式是 byte[] 本身 :)

【讨论】:

  • 如果您需要通过网络发送 Base64 编码的表单怎么办?或文件?那么你需要把它翻译成字节[]。不要太快说没有意义的事情。
  • @AmitBens 当然,但是如果 API 需要一个字节 [],那么您通常可以发送原始字节。也许您正在考虑将 byte[] 嵌入文本结构(例如 JSON)中,然后通过二进制协议(例如 TCP)发送更大的结构的情况?您几乎不需要直接将字节数组转换为 base64,只需再次将其转换回 byte[]。
  • @erenEsonmez - MIME 用于电子邮件发送,使用 base64 用于附件或非 ascii 编码的消息等。如果不通过网络发送 base64 表示,您几乎无法发送电子邮件。
  • @ErenErsönmez 另请注意,某些 API 要求以 Base64 字符串形式提供数据(例如 shopify)。我同意它很愚蠢,但这就是人们可能需要它的原因。
【解决方案3】:

这是直接将 base64 编码为字节数组的代码(经测试执行 +-10% 的 .Net 实现,但分配了一半的内存):

    static public void testBase64EncodeToBuffer()
    {
        for (int i = 1; i < 200; ++i)
        {
            // prep test data
            byte[] testData = new byte[i];
            for (int j = 0; j < i; ++j)
                testData[j] = (byte)(j ^ i);

            // test
            testBase64(testData);
        }
    }

    static void testBase64(byte[] data)
    {
        if (!appendBase64(data, 0, data.Length, false).SequenceEqual(System.Text.Encoding.ASCII.GetBytes(Convert.ToBase64String(data)))) throw new Exception("Base 64 encoding failed");
    }

    static public byte[] appendBase64(byte[] data
                              , int offset
                              , int size
                              , bool addLineBreaks = false)
    {
        byte[] buffer;
        int bufferPos = 0;
        int requiredSize = (4 * ((size + 2) / 3));
        // size/76*2 for 2 line break characters    
        if (addLineBreaks) requiredSize += requiredSize + (requiredSize / 38);

        buffer = new byte[requiredSize];

        UInt32 octet_a;
        UInt32 octet_b;
        UInt32 octet_c;
        UInt32 triple;
        int lineCount = 0;
        int sizeMod = size - (size % 3);
        // adding all data triplets
        for (; offset < sizeMod;)
        {
            octet_a = data[offset++];
            octet_b = data[offset++];
            octet_c = data[offset++];

            triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

            buffer[bufferPos++] = base64EncodingTable[(triple >> 3 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 2 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 1 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 0 * 6) & 0x3F];
            if (addLineBreaks)
            {
                if (++lineCount == 19)
                {
                    buffer[bufferPos++] = 13;
                    buffer[bufferPos++] = 10;
                    lineCount = 0;
                }
            }
        }

        // last bytes
        if (sizeMod < size)
        {
            octet_a = offset < size ? data[offset++] : (UInt32)0;
            octet_b = offset < size ? data[offset++] : (UInt32)0;
            octet_c = (UInt32)0; // last character is definitely padded

            triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

            buffer[bufferPos++] = base64EncodingTable[(triple >> 3 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 2 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 1 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 0 * 6) & 0x3F];

            // add padding '='
            sizeMod = size % 3;
            // last character is definitely padded
            buffer[bufferPos - 1] = (byte)'=';
            if (sizeMod == 1) buffer[bufferPos - 2] = (byte)'=';
        }
        return buffer;
    }

【讨论】:

  • 感谢您以艰难的方式做到这一点。但我会坚持使用 System.Convert。
  • @FlorianFida 当然! System.Convert 的缺点是当您需要将 Base64 放入更大的缓冲区时,您最终会分配额外的缓冲区(如果您的大小> 80k,则很容易污染 LOH/GC),但只要代码不是非常使用通常,保留您的系统方法绝对安全:)
  • Amit Bens 代码具有良好的性能,但直到您需要将结果转换为字符串或 char[](表示 UTF16)。这种情况经常发生。然后你会发现它比 System.Convert.ToBase64String 慢两倍。只是因为最后有一个 System.Text.Encoding.ASCII.GetString(bytes) 。这对我来说是非常出乎意料的。
【解决方案4】:
byte[] base64EncodedStringBytes = Encoding.ASCII.GetBytes(Convert.ToBase64String(binaryData))

【讨论】:

    【解决方案5】:

    根据您的编辑和 cmets.. 这就是您所追求的吗?

    byte[] newByteArray = UTF8Encoding.UTF8.GetBytes(Convert.ToBase64String(currentByteArray));
    

    【讨论】:

    • 我们知道 base-64 字符串将在 ASCII 范围内,因此直接使用 ASCII 编码可能更有效(因为它与 UTF8 产生的相同) )
    【解决方案6】:

    您可以使用 String Convert.ToBase64String(byte[]) 将字节数组编码为 base64 字符串,然后使用 Byte[] Convert.FromBase64String(string) 将生成的字符串转换回字节数组。

    【讨论】:

      【解决方案7】:

      将图像从字节检索到 base64 字符串....

      模型属性:

          public byte[] NomineePhoto { get; set; }
      
          public string NomineePhoneInBase64Str 
          {
              get {
                  if (NomineePhoto == null)
                      return "";
      
                  return $"data:image/png;base64,{Convert.ToBase64String(NomineePhoto)}";
              } 
          }
      

      在视图中:

         <img style="height:50px;width:50px" src="@item.NomineePhoneInBase64Str" />
      

      【讨论】:

        【解决方案8】:
            public void ProcessRequest(HttpContext context)
            {
                string constring = ConfigurationManager.ConnectionStrings["SQL_Connection_String"].ConnectionString;
                SqlConnection conn = new SqlConnection(constring);
                conn.Open();
                SqlCommand cmd = new SqlCommand("select image1 from TestGo where TestId=1", conn);
                SqlDataReader dr = cmd.ExecuteReader();
                dr.Read();
                MemoryStream str = new MemoryStream();
        
                context.Response.Clear();
                Byte[] bytes = (Byte[])dr[0];
                string d = System.Text.Encoding.Default.GetString(bytes);
                byte[] bytes2 = Convert.FromBase64String(d);
                //context.Response.Write(d);
                Image img = Image.FromStream(new MemoryStream(bytes2));
                img.Save(context.Response.OutputStream, ImageFormat.Png);
                context.Response.Flush();
                str.WriteTo(context.Response.OutputStream);
                str.Dispose();
                str.Close();
                conn.Close();
                context.Response.End();
            }
        

        【讨论】:

        • 我可以看到你的回答被否决了。请解释您的答案,以避免将来遭到社区的反对。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-04
        相关资源
        最近更新 更多