X

base64细节

2022/6/28

base64 相信大家都很熟悉了 在浏览器有内置的atob解码和btoa转换

但是其具体是如何实现的呢?

首先base64 有一个编码表

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

base64字符串的每一个字母对应的值是对应字母的下标

比如我这里有一段base64字符串

data:text/plain;base64,aGVsbG8gd29ybGQ=

其中 aGVs 就对应 26 6 21 44

然后 字符串一个字节是8bit base64每四个字节对应原始数据的三个字节

原始数据->base64数据

1.原始字节每三个的二进制数据按6位一组分开 分成4个

2.然后左侧补零补成8位 即变成4字节

3.每字节对应编码表对应位置的字符

举个栗子

原始字符串 ABC
转换ASCII 65 66 67
对应二进制 01000001 01000010 01000011
合并 010000010100001001000011
分割 010000 010100 001001 000011
补零 00010000 00010100 00001001 00000011
十进制 16 20 9 3
对应编码表 Q U J D

我们可以验证一下:

console.log(btoa('ABC')) //QUJD

如果不能完整分割三字节怎么办?

当然是补零 补充到可以完整分割即可

ps: 如果改变编码表我们也能拥有自己的一套简单加密

实践

来一个按钮 我们点击它 它能下载base64文件

正常来说 href填上base64地址就好了

但这次我们画蛇添足一下 我们先转成文件格式 然后下载 下载是当初期望内容即证明无误

<a>Download</a>

先初始化对照表

  const b64Dic = {};
    [].forEach.call(
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
        (a, i) => b64Dic[a] = i
    );

然后实现base64转原始字节算法

    function base64ToFile(base64Str) {
        const [ext, data] = base64Str.substring(5).split(';base64,');
        const raw = new Array(data.length / 4 * 3);
        let i = 0;
        data.match(/.{4}/g).forEach(c => {
            const [v0, v1, v2, v3] = [].map.call(c, a => b64Dic[a])
            console.log(v0,v1,v2,v3)
            
            raw[i] = (v0 << 2) + (v1 >> 4);
            raw[i + 1] = ((v1 & 0b1111) << 4) + (v2 >> 2)
            raw[i + 2] = ((v2 & 0b11) << 6) + v3
            i += 3
        });
        let l = raw.length
        while (--l) {
            if (raw[l]) {
                break
            }
        }
        const bytes = Uint8Array.from(raw.slice(0, l + 1))
        const now = Date.now()
        return new File([bytes], 'file', {lastModified: now, type: ext});
    }

最后生成文件连接 放到下载处

    const file = base64ToFile('data:text/plain;base64,aGVsbG8gd29ybGQ=');
    const a = document.querySelector('a');
    a.download = 'down.txt'
    a.href = URL.createObjectURL(file);
Commit