Base64 只改变你的数据看起来的样子,从不改变它是什么。你带来字符串或文件,我们来处理解码或编码的流程。我们的工具就在下方,再往下滚动一次就是 Base64 解析。

编码为 Base64 格式

要对二进制文件(如图像、文档等)进行编码,请使用此页面下方的文件上传表单。

将文件编码为 Base64 格式

0 单击(或轻触)此处选择文件
文件大小上限为 100MB。
正在运行...
请等待编码过程完成。
成功!
{{ output }} 下载编码文件。
请注意,在第一次尝试下载或持续 15 分钟无操作后,此文件将立即从系统中删除。
错误!
{{ error }}

概览

Base64 是一种可逆变形,而这个工具是这段旅程的前半程:它接收你能输入的任何内容或能上传的任何文件,把它们改写成可打印文本,在邮件、URL 和 JSON 文档里原样幸存,一个字节都不少。粘贴一些数据,挑一种你喜欢的 Base64 口味,编码结果就准备好供你复制了。与之配套的解码器就在姊妹网站上,隔着一个链接。

高级选项

  • 字符集:你的文本到达我们这里时永远是 UTF-8,默认也按 UTF-8 编码。当接收方期待不同的字节时更改这个列表,比如给遗留 Windows 程序用 Windows-1252,给较老的欧洲软件用某个 ISO-8859 变体:转换发生在编码之前,所以你拿到的字符串携带的正是你要求的字节。记得告诉解码器你选了哪一套,因为 Base64 本身从不说明。文件表单里列表以 BINARY(不转换)开头,除纯文本外,它是一切场景的正确选择。
  • 换行分隔符:Unix 和 Windows 对如何结束一行意见不一,你的输入可能带着其中一种(或两种都带)。在编码开始之前,文本中的每个换行都会被改写成你在这里挑选的样式,所以无论数据来自哪里,编码后的数据内容都保持一致。当两个多行选项之一打开时,同一个分隔符也用来拼接输出的各行。对于上传的文件,字节保持原样;分隔符只决定编码后的输出如何分行。
  • 对每一行分别编码:通常整个输入作为一个整体编码,换行也包含在内,这正是大多数应用所期望的。当输入是一批相互独立的条目时启用它:每一行各自编码,编码后的各行再用你选择的那个分隔符拼回一起。(*)
  • 将行拆分为组块:一条新鲜的 Base64 字符串是一整行,这适合大多数系统,但不是全部:MIME 规范(RFC 2045)规定编码行不应超过 76 个字符,而邮件尤其希望它们短一些。勾选这个选项,输出就按每行 76 个字符折行,使用你选择的那个分隔符。(*)
  • 执行 URL 安全编码:标准字符表里的两个字符 + 和 / 在 URL 里待得不舒服,= 填充符更是雪上加霜。这个选项改为采用 RFC 4648 的 Base64URL 变体:+ 变成 -,/ 变成 _,填充符则被整个去掉,因为它们可以根据长度推算出来。结果更短,放进 URL、文件名和 JSON Web Tokens 都不用任何转义。记得告诉解码器你选了哪个方言就行。
  • 实时模式:打开它之后,编码会在你的浏览器里随你输入实时进行,每敲一个键就重新运行一次,什么都不会发送到我们的服务器。它会跟随你逐个切换其他选项(逐行、组块、URL 安全),且只支持 UTF-8,所以开启期间字符集列表保持锁定,编码按钮也保持禁用,直到你切换回来。

(*)这些选项不能同时启用,因为产生的输出对大多数应用来说将无效。表单会替你处理:勾选其中一个就会禁用另一个。

安全可靠

所有操作都通过加密的 HTTPS 连接进行,你提交的任何内容都不会被保留:上传的文件在处理完成的瞬间就被删除,可下载的结果也会在你第一次尝试下载之后、或 15 分钟无操作之后(以先到者为准)随即消失。你发送的内容本身从不被存储,除了转换本身也不会被查看。开启实时模式后,你的文本永远不会离开浏览器。完整细节见我们的隐私政策,链接就在下方页脚里。

完全免费

本页面的所有功能都可以免费使用——完整的字符集列表、文件上传和实时模式全都包含在内。无需账号、无需安装软件、没有付费墙:这么小的一件事,本就该如此。

Base64 解析

有些数据天生就无法通过纯文本通道传输:一张照片、一个压缩包、一个哈希值、一段足以让 7 位邮件连接卡死的二进制。Base64 就是为这样的时刻而生的翻译官。它把任何一长串字节改写成朴素的可打印文本,让数据可以待在邮件正文、JSON 文档、XML 文件或 URL 里,抵达时与出发时一模一样。这种翻译完全可逆:每一个字节都会回来,顺序不变,一路上没有任何丢失。

整个格式可以浓缩成一句话:三个字节进,四个字符出。代价是结果比原始数据大约大三分之一。回报是一个看起来像文本、行为也像文本、还能在会摧毁原始字节的通道里幸存的字符串。而且值得尽早说清楚 Base64 不是什么:它不是加密,也不是压缩。它是一种可逆变形,这就是它的全部职责。

为什么是 64,为什么是这些字符

一个字节容纳 8 位,但老旧的文本通道(尤其是邮件)只能安全地携带 7 位 ASCII。诀窍在于挑选一组能经受住这样旅途的可打印字符作为字符表,并且把规模定得让数学恰好整除。64 个字符意味着每个编码字符恰好携带 6 位,而 24 既能被 8(字节)整除,也能被 6(字符)整除:三个输入字节变成四个输出字符,什么都不剩下。这个名字只是那套字符算术的底数,就像我们数字里的十进制一样。

标准字符表是 62 个字母数字字符:A 到 Z、a 到 z、0 到 9,最后两个是 + 和 /。规范额外增加了一个第 65 个字符 =,它根本不属于字符表:它只会出现在末尾,作为填充。这个选择是刻意为之。整套字符都是可打印的;它存在于每一个文本系统中;而且 MIME 规范指出,它在 ISO 646 的每一个版本(包括 US-ASCII)以及 EBCDIC 的每一个版本中拼写完全相同。正是最后这个特性,让数据在穿越互联网上那些不支持 8 位的老旧设备时保持完好。

值 字符 值 字符 值 字符 值 字符
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /
(第 65 个字符 = 是填充符:它从不携带数据,只用来标记末尾。)

编码,逐步拆解

编码器是一条四道工序的流水线。它每次读取输入中的三个字节,把每个三字节组合并成一串 24 位。这串位再被切成四段,每段 6 位。每一段都是 0 到 63 之间的一个数字,每个数字都在上表中查一次。四个数字进,四个字符出。

拿单词 foo 看它是如何发生的:它到达时的字节值是 102、111 和 111(十六进制 66、6F、6F)。首尾相接后,这 24 位是 01100110 01101111 01101111。按 6 位一组切开,就是 011001、100110、111101 和 101111,分别是 25、38、61 和 47。查表可知它们对应 Z、m、9 和 v,所以 foo 编码为 Zm9v,世界上任何 Base64 解码器都能把它还原回原来的三个字节。

步骤 第 1 个字节 第 2 个字节 第 3 个字节
文本 f o o
字节值 102 111 111
十六进制 66 6F 6F
位 0 1 1 0 0 1 1 0 0 1 1 0 1 1 1 1 0 1 1 0 1 1 1 1
6 位值 25 38 61 47
字符 Z m 9 v

其余的输入以同样的方式处理,一组三字节接一组三字节,直到用完为止。只有最后一组,当它不足三个字节时,才需要一招特别的处理。

填充:末尾的 =

输入的字节总数总是整数,但不一定能被 3 整除。当末尾剩下 1 或 2 个字节时,编码器仍然要凑满一组四个字符。它会用零填满缺失的位,照常查表,再把填充位本应产生的字符替换成 = 号。末尾恰好只有三种可能:

输入末尾 编码后末尾 解码回
3 个字节 4 个字符,无填充 3 个字节
2 个字节 3 个字符 + 1 个 = 2 个字节
1 个字节 2 个字符 + 2 个 = 1 个字节

所以 fo(两个字节)变成 Zm8=,孤独的 f 变成 Zg==,而 foo 则完全不需要填充。解码器对填充符该做什么一清二楚:每个 = 意味着还要丢掉 8 个零位。填充符永远只坐在最末尾,而且最多只有两个。MIME 规范甚至把这当作一个特性来用:既然 = 不可能出现在别处,带填充的数据内容就自带结尾标记,接收方由此知道数据在传输途中没有被截断。至于最小的情况:空输入编码为空输出。哪怕什么都没有,也能完成一次完美的往返。

解码:流水线倒转

解码就是同一台机器倒着运行,同样机械。取四个字符,把真正的字符查表(填充符顶替六个零),写出 24 位,然后:如果有一个填充符就交还前 16 位,没有填充符就交出全部 24 位。四个字符进,三个字节出;带一个填充符出两个字节;带两个填充符出一个字节。编码器补上的那些零位是唯一被丢掉的东西,其余每一位都原封不动。这里可逆的真正含义就是:格式本身是无损的,唯一能伤害你数据的,要么是损坏了这个字符串的通道,要么是悄悄放弃的解码器。

这就是为什么标准对一件事特别严格:不在字符表里的字符。RFC 4648 规定,解码器必须拒绝任何包含 64 个字符之外字符的数据内容,除非周围的规范明确允许。原因是务实的,不是抠字眼。一个悄悄吞下外来字符的解码器可能会被套路:夹带的字符变成一条隐蔽的旁路通道,而这招已经被用来向过滤器隐藏数据,也用来试探解码器的漏洞。著名的例外是 MIME 本身,它早于这个标准,说法正好相反:忽略所有字符表之外的字符,邮件附件里的换行就是这样穿过去的。当你自己校验输入时,现代规则才是对的:如果你的字符串里带着 @、一个空格,或者任何不在表里的东西,那它就不是干净的 Base64。

换行与 76 字符规则

你经常会见到折了行的 Base64,这个习惯来自邮件。老式 SMTP 设备对行长有限制,所以 MIME 把数据内容按每行 76 个字符、用 CRLF 换行来折行,而更老的 PEM 格式(就是承载证书和密钥的那个)按 64 个字符折行。RFC 4648 给新代码定的规则正好相反:除非你要实现的格式明确要求,否则一律不加换行。实际上,解码器并不在意。换行只是一个字符表之外的字符,所以 MIME 折行过的数据内容、PEM 块、还是一条长到不折行的字符串,解码出来都是同样的字节。如果你从任何地方粘贴了 Base64,先把换行去掉,这事就办完了。

折行有一点小代价,它会体现在体积计算里。不加换行时,Base64 恰好是原始体积的三分之四,大约大 33%。按每行 76 个字符加 CRLF 换行折行后,大约大 37%,这就是为什么一个本该是 100 KB 的文件,常常以大约 137 KB 的文本形式到达。这笔账永远算得平。

Base64URL:URL 安全的双胞胎

标准字符表里有两个字符与 URL 处不来。查询字符串里的 + 传统上被读作空格,/ 是路径分隔符,所以一条原始 Base64 字符串放进 URL 时,这两者外加 = 填充符都得做百分号转义。RFC 4648 第 5 节定义了修复方案:URL 和文件名安全字符表,其中 + 变成 -,/ 变成 _。填充符通常也一并省掉,因为缺了填充可以根据长度推算出来。RFC 明确说,这个不该被称为普通的 Base64:它是另一种编码,通常写作 base64url。

实际中,两者只差一次替换,而且方向是危险的。把一条 base64url 字符串喂给标准解码器,结果会出错,因为 - 和 _ 不在标准字符表里:宽松的解码器会把它们丢掉,返回一个更短、且错误的字节串,或者,当剩余部分短到无法独立成字节时,返回一个错误;而严格的解码器会拒绝整个数据内容。正确的舞步是:先把 - 换回 +、_ 换回 /,补齐缺失的填充符,然后才解码。你在 JSON Web Tokens(JWT)、OAuth 状态字符串,以及某家超级大视频网站的 ID 里,见到的就是这一方言。

一份快速实用指南

还没伸手去拿工具之前,你可以自己读出这条字符串里的很多信息。几个小检查就能告诉你,一个数据内容到底是不是 Base64,以及它藏着什么:

  • 看字符。标准 Base64 只使用 A 到 Z、a 到 z、0 到 9、+ 和 /;URL 安全的双胞胎则用 - 和 _ 替换后两个。出现任何其他符号,或一个多余的空格,就说明它不是干净的 Base64。
  • 查填充符。= 号如果出现,只坐在最末尾,而且最多两个。字符串中间出现填充符是危险信号。
  • 数长度。带填充符时,长度总是 4 的倍数。不带填充符时,长度除以 4 的余数是 0、2 或 3。余数为 1 是不可能的,因为一个字符只携带 6 位,而一个字节需要 8 位。
  • 估大小。每 4 个字符一组承载 3 个字节,每有一个 = 号就少一个字节。所以 Zm9vYmFy(8 个字符,无填充)是 6 个字节,Zm9vYg==(8 个字符,两个填充)是 4 个字节。

最后还有一个实战技巧,也是最管用的。编码器必须把填充位清零,但宽松的解码器不检查它们。数据内容 Zg== 解码为单个字节 f,Zh== 解码出来也一样:最后一个字符的低位在这两种情况下都是填充位,所以两者拼出的是同一个字节。标准称零位版本为标准形式,这让严格的解码器能够拒绝另一种。两条字符串,一份数据。如果两个系统对某个 Base64 值看法不一致,填充位是很好的排查起点。

Base64 不是什么

  • 不是加密。没有密钥,也没有秘密;任何人都能在一秒内把 Base64 字符串还原成字节。RFC 甚至提到过真实事件:有人报告协议交互中包含“已编码”的密码,还深信编码把它藏了起来。如果数据敏感,请在编码之前就用真正的密码学保护好它,而不是之后。
  • 不是压缩。方向正好相反:结果比输入大约大 33%,加上换行后还要更大。Base64 为你买来文本安全,账单则按体积结算。
  • 不是字符集。Base64 搬运的是字节,不是字母。它不知道也不在乎那些字节是 UTF-8 文本、旧的单字节编码,还是一张 JPEG。“这到底是什么字符集?”这个问题只存在于编码之前和解码之后,从不在其中。
  • 不是唯一一种编码。这个名字覆盖的是一个家族:标准字符表、URL 安全的双胞胎、按 76 或 64 个字符折行的数据内容、省掉填充符的变体,以及一堆怪胎(比如 IMAP 在编码国际邮箱名时,用逗号替换字符表里的 /)。当两个系统对一份数据内容各执一词时,方言差异通常就是罪魁祸首。

细则

一手资料都很简短,也好读。RFC 4648 《Base16、Base32 和 Base64 数据编码》(2006 年)是现行标准:两套字符表、填充与换行规则、严格性规则,以及一组官方测试向量(比如 foo 变成 Zm9v),实现都拿它们来检验自己。站在它身后的是 RFC 2045,1996 年的 MIME 规范,76 字符行规则和对杂散字符的宽容就出自这里;还有 RFC 1421,已弃用的 Privacy Enhanced Mail 规范,这个家族最早由它以 64 字符行起家。更早的一次统一尝试 RFC 3548,已被 RFC 4648 取代。

故事就是全部:64 个字符,三个字节进、四个字符出,= 收尾,一次完美的往返。你今后遇到的每一个工具、每一个库、每一个在线转换器,都只是通向这里的一扇门。一旦你能看着一条 Base64 字符串、看见它身后站着的字节,这个格式再也不会让你感到意外。而当你准备好自己动手写编码器时,紧接在本节下方的编程语言文章会把同样的 64 个字符以可运行代码的形式交到你手上:每种语言一篇完整指南。