跳到内容

为什么 Base64 编码会导致文件大小增加 33%

分类:编码

你有没有听说过「用 Base64 编码后文件大小会增加约 33%」这种说法?为什么会这样呢?本文将讲解 Base64 编码的工作原理、文件大小增加的数学原因,以及在实际开发中的影响。

什么是 Base64

Base64 是一种编码方案,它仅使用 ASCII 字符来表示二进制数据。它用于在纯文本协议上传输二进制数据,例如电子邮件附件(MIME)、数据 URI 方案、JWT 令牌和基本身份验证标头。

使用的字符包括 A–Z(26个字符)、a–z(26个字符)、0–9(10个字符)、+/,共64个字符(= Base64),加上用于填充的 =

为什么增加33%

Base64 将 3 字节的二进制数据转换为 4 个 ASCII 字符

  • 3字节 = 24位
  • 24位 ÷ 6位 = 4个Base64字符(每个字符表示6位)

也就是说,原始数据变成 3字节 → 4个字符。大小比例是 4 ÷ 3 ≈ 1.333...,所以 大约增加33.3%

元バイナリ:   | 0x4D | 0x61 | 0x6E |  ← 3バイト
              01001101 01100001 01101110
              ↓ 6ビットずつに分割
              010011 010110 000101 101110
              ↓ Base64文字に変換
                 T       W       F       u   ← 4文字(= 4バイト)

具体大小增长的计算

原始文件大小Base64 之后的大小增加量
1 MB(1,000,000 B)约 1.333 MB+333 KB
10 MB约 13.33 MB+3.33 MB
25 MB(Gmail限制)约 33.3 MB+8.33 MB
100 MB约 133.3 MB+33.3 MB

确切的计算公式如下。

import math

def base64_size(original_bytes: int) -> int:
    """Base64エンコード後のバイト数を計算"""
    # 3バイトを4文字に変換、4の倍数にパディング
    return math.ceil(original_bytes / 3) * 4

original = 10_000_000  # 10 MB
encoded  = base64_size(original)
print(f"元: {original:,} B")
print(f"後: {encoded:,} B")
print(f"増加率: {encoded/original*100:.1f}%")
# → 元: 10,000,000 B
# → 後: 13,333,336 B
# → 増加率: 133.3%

由换行字符引起的进一步增加

MIME 标准(电子邮件)要求 Base64 数据每 76 个字符用 \r\n (CRLF) 换一行。这些换行符也添加额外的字节,略微增加整体大小。

def base64_mime_size(original_bytes: int, line_length: int = 76) -> int:
    """MIME形式(76文字改行)のBase64サイズを計算"""
    b64_chars = math.ceil(original_bytes / 3) * 4
    line_count = math.ceil(b64_chars / line_length)
    return b64_chars + line_count * 2  # CRLF = 2バイト/行

对开发的影响

通过 API 传输文件

通过 REST API 在 JSON 正文中发送文件时,需要进行 Base64 编码。

// ファイルをBase64に変換してJSONで送る
const file = document.getElementById('file').files[0];
const reader = new FileReader();
reader.onload = (e) => {
    const base64 = e.target.result; // "data:image/png;base64,iVBORw0KGgo..."
    fetch('/api/upload', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ file: base64, name: file.name })
    });
};

在这种情况下,API的请求大小限制由Base64编码的大小决定。请注意,发送10MB文件时,JSON正文将约为13.3MB或更大。

电子邮件附件 (SMTP)

由于 SMTP 协议基于 ASCII 文本,附件会被编码为 Base64。Gmail 的附件限制为 25MB,这是指编码前的文件大小(Gmail 处理内部编码)。但是,当通过 SMTP 直接发送时,大小限制适用于编码后的大小,因此需要注意。

img 标签的数据 URI

<!-- Base64埋め込み画像 -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." />

在 HTML 中内联嵌入图像时,HTML 文件会增大相当于图像 Base64 大小的空间。通常建议避免内联嵌入大型图像,因为这会影响页面加载速度。

解码 Base64 并恢复到原始大小

总结

  • Base64 将3 字节 → 4 个字符进行转换,导致大小增加约 33.3%
  • 当存在 MIME 换行符(每 76 个字符)时,会进一步略微增加
  • 对于通过 JSON 正文发送文件的 API,请求限制由 Base64 后的大小决定
  • HTML 表单的 multipart/form-data 不需要 Base64 编码(二进制直接发送)

本文中可用的测试文件

❓ 常见问题

Base64 编码为什么会让文件增大 33%?
Base64 将每 3 字节二进制转换为 4 个 ASCII 字符,比例为 4/3 ≈ 1.333,因此体积增加约 33.3%。MIME 规范每 76 个字符追加一次 CRLF 换行,会再略微增加。
通过 API 发送 Base64 编码文件时,需要注意哪些大小限制?
API 的请求大小限制针对编码后的载荷。以 JSON 发送 10MB 文件时,请求体至少约 13.3MB。而 HTML 表单的 multipart/form-data 直接发送二进制、无需 Base64,开销仅数百字节。
如何计算 Base64 编码后的文件大小?
公式为「原字节数除以 3 向上取整,再乘以 4」。10,000,000 字节(10MB)的文件编码后为 13,333,336 字节(约 13.3MB)。MIME 格式还需为每 76 个字符的 CRLF 各加 2 字节。