跳到内容

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

分类:编码
本文目前仅提供日文版本。我们正在进行翻译工作。

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

什么是 Base64

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

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

为什么增加33%

Base64 <strong>将 3 字节的二进制数据转换为 4 个 ASCII 字符</strong>。

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

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

元バイナリ:   | 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 个字符用 <code>\r\n</code> (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编码<em>后</em>的大小决定。请注意,发送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 将<strong>3 字节 → 4 个字符</strong>进行转换,导致大小<strong>增加约 33.3%</strong>
  • 当存在 MIME 换行符(每 76 个字符)时,会进一步略微增加
  • 对于通过 JSON 正文发送文件的 API,请求限制由 Base64 后的大小决定
  • HTML 表单的 <code>multipart/form-data</code> 不需要 Base64 编码(二进制直接发送)

本文中可用的测试文件

  • → <a href="/ja/files/images/png/" class="text-primary-600 dark:text-primary-400 hover:underline">PNG 图像测试文件列表</a>
  • → <a href="/ja/files/pdf/" class="text-primary-600 dark:text-primary-400 hover:underline">PDF 测试文件列表</a>

相关文章

  • → <a href="/ja/blog/multipart-form-data-overhead/" class="text-primary-600 dark:text-primary-400 hover:underline">准确计算 multipart/form-data 的开销</a>
  • → <a href="/ja/blog/file-format-quick-reference/" class="text-primary-600 dark:text-primary-400 hover:underline">开发者文件格式快速参考</a>