Base64长度计算?

读取base64 wiki

我试图找出怎么样公式工作:

给定一个长度为n的字符串,base64长度为enter image description here

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

我已经知道base64长度必须是%4==0,以允许解码器知道原始文本的长度。

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

wiki:每个输入字节的输出字节数大约是4 / 3 (33%) 开销)< / p >

问题:

如何以上信息是否与输出长度一致enter image description here ?

269450 次浏览

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

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

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

由于四舍五入到4的倍数而导致的未使用填充字符的数量显然是0、1、2或3。

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

Base64 encoder's length formula

如前所述,给定n字节的数据的Base64编码器将生成4n/3 Base64字符的字符串。换句话说,每3个字节的数据将导致4个Base64字符。__abc3: __abc4 __abc5。

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

你在注释中问编码123456的大小是多少。请记住,该字符串的每个字符的大小都是1字节或8位(假设ASCII/UTF8编码),我们正在编码6字节或48位的数据。根据公式,我们期望输出长度为(6 bytes / 3 bytes) * 4 characters = 8 characters

123456放入Base64编码器中创建MTIzNDU2,正如我们所期望的那样,它有8个字符长。

我认为给出的答案忽略了原始问题的重点,即需要分配多少空间来适合长度为n字节的给定二进制字符串的base64编码。

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

这包括填充和终止空字符。如果你在做整数运算,你可能不需要楼层调用。

包括填充在内,base64字符串需要为原始字符串的每3字节块(包括任何部分块)提供4个字节。当添加填充时,字符串末尾的一个或两个额外字节仍然会转换为base64字符串中的四个字节。除非你有非常特殊的用途,否则最好添加填充,通常是等号。我在C语言中为空字符添加了一个额外的字节,因为没有它的ASCII字符串有点危险,您需要单独携带字符串长度。

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

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

4 * n / 3给出无填充长度。

并四舍五入到最接近4的倍数进行填充,因为4是2的幂,可以使用逐位逻辑运算。

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

在windows中-我想估计mime64大小的缓冲区的大小,但所有精确的计算公式都不适合我-最后我得到了这样的近似公式:

Mine64字符串分配大小(近似) =(((4 *((二进制缓冲区大小)+ 1)/ 3)+ 1)< / p >

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

当其他人都在讨论代数公式时,我宁愿用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字符表示的公式似乎是正确的。

如果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]

玩得开心

胃肠道

整数

通常我们不想使用双精度数,因为我们不想使用浮点运算,舍入错误等。他们只是没有必要。

为此,最好记住如何执行上限除法:双数的ceil(x / y)可以写成(x + y - 1) / y(同时避免负数,但要注意溢出)。

可读的

如果你追求可读性,你当然也可以像这样编程(例如在Java中,对于C你当然可以使用宏):

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个字节(或更少)需要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

然而,我们仍然可以除以2(如果我们愿意的话):

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

不可读的

如果你不相信你的编译器会为你做最终的优化(或者如果你想让你的同事困惑):

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

填充物的

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

所以我们有两种逻辑计算方式,我们不需要任何分支,位运算或模运算,除非我们真的想这样做。

注:

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

下面是一个函数来计算一个base64编码文件的原始大小为KB的字符串:

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;
}

简单的javascript实现

function sizeOfBase64String(base64String) {
if (!base64String) return 0;
const padding = (base64String.match(/(=*)$/) || [])[1].length;
return 4 * Math.ceil((base64String.length / 3)) - padding;
}

如果有人有兴趣在JS中实现@Pedro Silva解决方案,我只是为它移植了相同的解决方案:

const getBase64Size = (base64) => {
let padding = base64.length
? getBase64Padding(base64)
: 0
return ((Math.ceil(base64.length / 4) * 3 ) - padding) / 1000
}


const getBase64Padding = (base64) => {
return endsWith(base64, '==')
? 2
: 1
}


const endsWith = (str, end) => {
let charsFromEnd = end.length
let extractedEnd = str.slice(-charsFromEnd)
return extractedEnd === end
}

对于所有会说C语言的人,看看这两个宏:

// calculate the size of 'output' buffer required for a 'input' buffer of length x during Base64 encoding operation
#define B64ENCODE_OUT_SAFESIZE(x) ((((x) + 3 - 1)/3) * 4 + 1)


// calculate the size of 'output' buffer required for a 'input' buffer of length x during Base64 decoding operation
#define B64DECODE_OUT_SAFESIZE(x) (((x)*3)/4)

取自在这里

(试图给出一个简洁而完整的推导。)

每个输入字节都有8位,因此对于n输入字节,我们得到:

n × 8输入位

每6位是一个输出字节,因此:

装天花板 (n×8/6)= 装天花板 (n×4 / 3 )      输出字节

这是没有填充的。

对于填充,我们四舍五入为四个输出字节中的多个:

装天花板 (装天花板 (n×4 / 3)/ 4)×4 = 装天花板 (n×4 / 3 / 4)×4 = 装天花板 (n / 3)×4字节输出

请参阅嵌套的分歧(维基百科)的第一个等价。

使用整数算术, cell (n / m)可以计算为(n + m - 1) div m, 因此我们得到:

(n * 4 + 2) div 3没有填充

(n + 2) div 3 * 4与填充

说明:

 n   with padding    (n + 2) div 3 * 4    without padding   (n * 4 + 2) div 3
------------------------------------------------------------------------------
0                           0                                      0
1   AA==                    4            AA                        2
2   AAA=                    4            AAA                       3
3   AAAA                    4            AAAA                      4
4   AAAAAA==                8            AAAAAA                    6
5   AAAAAAA=                8            AAAAAAA                   7
6   AAAAAAAA                8            AAAAAAAA                  8
7   AAAAAAAAAA==           12            AAAAAAAAAA               10
8   AAAAAAAAAAA=           12            AAAAAAAAAAA              11
9   AAAAAAAAAAAA           12            AAAAAAAAAAAA             12
10   AAAAAAAAAAAAAA==       16            AAAAAAAAAAAAAA           14
11   AAAAAAAAAAAAAAA=       16            AAAAAAAAAAAAAAA          15
12   AAAAAAAAAAAAAAAA       16            AAAAAAAAAAAAAAAA         16

最后,以MIME为例 Base64编码,每76个输出字节需要两个额外的字节(CR LF),四舍五入取决于是否需要结束换行符。

我在其他回答中没有看到简化的公式。逻辑是覆盖的,但我想要一个最基本的形式为我的嵌入式使用:

  Unpadded = ((4 * n) + 2) / 3


Padded = 4 * ((n + 2) / 3)

注意:当计算无填充计数时,我们四舍五入整数除法,即加上除数-1,在这种情况下是+2