为什么 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>