在阅读base64维基之后…

我想知道这个公式是怎么运作的

给定一个长度为n的字符串,base64的长度为

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

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

序列的最大填充数可以是=或==。

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

问题:

以上信息是如何与输出长度相匹配的?


当前回答

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

其他回答

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

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

整数

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

为此,最好记住如何执行上限除法:双数的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,您可能需要注意可能的行终止字符等(寻找其他答案)。

简单的javascript实现

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

4 * n / 3为无填充长度。

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

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

下面是一个函数来计算一个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;
}