Base64长度计算?

在阅读base64 维基 …

我想弄清楚公式是如何工作的:

给定一个长度为n的string,base64长度将是 在这里输入图像描述

它是: 4*Math.Ceiling(((double)s.Length/3)))

我已经知道base64的长度必须是%4==0才能让解码器知道原文的长度是多less。

一个序列的最大填充数可以是===

wiki:每个input字节的输出字节数约为4/3(开销33%)

题:

上面的信息如何与输出长度一致 在这里输入图像描述

每个字符用来表示6位( log2(64) = 6 )。

因此使用4个字符来表示4 * 6 = 24 bits = 3 bytes

所以你需要4*(n/3)字符来表示n个字节,这需要四舍五入到4的倍数。

由四舍五入到4的倍数而产生的未使用填充字符的数量显然将是0,1,2或3。

4 * n / 3给无衬垫的长度。

并且填充到4的最接近的倍数,并且作为4是2的幂可以使用按位逻辑操作。

 ((4 * n / 3) + 3) & ~3 

作为参考,Base64编码器的长度公式如下:

Base64编码器的长度公式

正如你所说的,给定n个字节数据的Base64编码器将产生一串4n/3 Base64字符。 换句话说,每3个字节的数据将导致4个Base64字符。 编辑评论正确地指出,我以前的graphics没有填充填充; 正确的公式是 Ceiling(4n/3)

维基百科的文章显示了如何在其示例中将ASCIIstringMan编码到Base64stringTWFu中。 input的string大小为3个字节或24位,因此公式正确地预测输出将是4个字节(或32位)长: TWFu 。 该过程将每6位数据编码为64个Base64字符之一,因此24位input除以6将得到4个Base64字符。

你在评论中要求123456编码的大小。 请记住,该string的每个字符都是1个字节或8个字节(假设为ASCII / UTF8编码),我们将编码6个字节或48个位的数据。 根据等式,我们预计输出长度为(6 bytes / 3 bytes) * 4 characters = 8 characters

123456放到一个Base64编码器中就会产生8个字符的MTIzNDU2 ,就像我们预料的那样。

我认为给定的答案错过了原来的问题,这是多less空间需要分配,以适应长度为n字节的给定二进制stringbase64编码。

答案是(floor(n / 3) + 1) * 4 + 1

这包括填充和终止空字符。 如果你正在做整数运算,你可能不需要发言权。

包括填充,base64string需要原始string的每个三字节块(包括任何部分块)的四个字节。 在添加填充时,string末尾的一个或两个字节仍然会被转换为base64string中的四个字节。 除非你有一个非常具体的用法,否则最好添加填充,通常是一个等号字符。 我在C中为空字符添加了一个额外的字节,因为没有这个string的ASCIIstring有点危险,你需要分别携带string长度。

整型

通常我们不想使用双打,因为我们不想使用浮点操作,舍入错误等,他们是没有必要的。

为此,记住如何执行上限划分是一个好主意:双精度上的ceil(x / y)可以写成(x + y - 1) / y (避免负数,但是要注意溢出)。

可读

如果你为了可读性,当然也可以这样编程(例如在Java中,对于C,当然可以使用macros):

 public static int ceilDiv(int x, int y) { return (x + y - 1) / y; } public static int paddedBase64(int n) { int blocks = ceilDiv(n, 3); return blocks * 4; } public static int unpaddedBase64(int n) { int bits = 8 * n; return ceilDiv(bits, 6); } // test only public static void main(String[] args) { for (int n = 0; n < 21; n++) { System.out.println("Base 64 padded: " + paddedBase64(n)); System.out.println("Base 64 unpadded: " + unpaddedBase64(n)); } } 

内联

加厚

我们知道每个3字节(或更less)我们需要4个字符块。 那么公式就变成了(对于x = n和y = 3):

 blocks = (bytes + 3 - 1) / 3 chars = blocks * 4 

或合并:

 chars = ((bytes + 3 - 1) / 3) * 4 

你的编译器会优化出3 - 1 ,所以就这样保持可读性。

不用护垫

不太常见的是无衬垫变体,为此我们记得每个我们需要一个6位的字符,四舍五入:

 bits = bytes * 8 chars = (bits + 6 - 1) / 6 

或合并:

 chars = (bytes * 8 + 6 - 1) / 6 

但是我们仍然可以分成两部分(如果我们想):

 chars = (bytes * 4 + 3 - 1) / 3 

不可读

如果你不相信你的编译器为你做最后的优化(或者你想混淆你的同事):

加厚

 ((n + 2) / 3) << 2 

不用护垫

 ((n << 2) | 2) / 3 

所以我们有两种逻辑的计算方法,除非我们真的想要,否则我们不需要任何分支,位操作或模运算。

笔记:

  • 显然,您可能需要在计算中加1以包含空终止字节。
  • 对于MIME,你可能需要注意可能的行结束字符等(​​查找其他答案)。

在我看来,正确的公式应该是:

 n64 = 4 * (n / 3) + (n % 3 != 0 ? 4 : 0) 

当其他人都在辩论代数公式时,我宁愿只用BASE64来告诉我:

 $ echo "Including padding, a base64 string requires four bytes for every three-byte chunk of the original string, including any partial chunks. One or two bytes extra at the end of the string will still get converted to four bytes in the base64 string when padding is added. Unless you have a very specific use, it is best to add the padding, usually an equals character. I added an extra byte for a null character in C, because ASCII strings without this are a little dangerous and you'd need to carry the string length separately."| wc -c 

525

 $ echo "Including padding, a base64 string requires four bytes for every three-byte chunk of the original string, including any partial chunks. One or two bytes extra at the end of the string will still get converted to four bytes in the base64 string when padding is added. Unless you have a very specific use, it is best to add the padding, usually an equals character. I added an extra byte for a null character in C, because ASCII strings without this are a little dangerous and you'd need to carry the string length separately." | base64 | wc -c 

710

所以看起来3个字节的公式由4个base64字符表示似乎是正确的。

这里是一个函数来计算编码的Base 64文件的原始大小,以KB为单位的string:

 private Double calcBase64SizeInKBytes(String base64String) { Double result = -1.0; if(StringUtils.isNotEmpty(base64String)) { Integer padding = 0; if(base64String.endsWith("==")) { padding = 2; } else { if (base64String.endsWith("=")) padding = 1; } result = (Math.ceil(base64String.length() / 4) * 3 ) - padding; } return result / 1000; } 

在Windows中 – 我想估计mime64大小的缓冲区的大小,但是所有精确的计算公式都不适用于我 – 最后我以如下近似公式为结束:

Mine64string分配大小(近似)=(((4 *((二进制缓冲区大小)+ 1))/ 3)+ 1)

所以最后+1 – 它用于ascii零 – 最后一个字符需要分配来存储零结束 – 但为什么“二进制缓冲区大小”是+ 1 – 我怀疑有一些mime64终止字符? 或者可能是这是一些alignment问题。

如果n%3不为零,我相信这个答案是确切的答案,否?

  (n + 3-n%3) 4 * --------- 3 

Mathematica版本:

 SizeB64[n_] := If[Mod[n, 3] == 0, 4 n/3, 4 (n + 3 - Mod[n, 3])/3] 

玩的开心

GI