如何将 Base64 解码为文件
- 把字符串粘贴到 Base64 或 data URI。标准 Base64 和 URL 安全的 Base64 都可以,有没有填充、换行或引号都没关系。完整的 data URI 可以用,包含 data URI 的文本也可以:CSS 的
url("data:…")、HTML 的src="data:…"或 Markdown 图片。如果长字符串保存在文件里,请使用 打开 .txt 文件 或把文件拖到输入框上。 - 查看输入框下方的状态行:输入是否有效、属于哪种变体(标准或 Base64URL)、解码后的大小以及 检测结果 中的类型。如果是 data URI,还会显示 声明的类型。
- 查看预览和下方的三个字段。文件名、扩展名 和 MIME 类型 会根据检测结果自动填写。你在这里填写的内容会一直保留,直到点击 清空。
- 点击 下载文件,或者点击 复制为 data URI,以
data:<MIME type>;base64,…的形式取回这些字节。
示例 每点一次会加载一个不同的测试文件:PNG、PDF、ZIP、WAV、DOCX、JSON、gzip 和 SVG。如果你拖入的文件本身已经是二进制文件,比如直接拖入 PDF,而不是存有其 Base64 的文本文件,工具会提示你,并给出 文件转 Base64 的链接,那个工具做的是反向转换。
为什么文件显示为 application/octet-stream
application/octet-stream 的意思是“一些字节,类型未知”。它出现在 Base64 前面的原因都很平常。对于浏览器不认识类型的文件,Chrome 的 FileReader.readAsDataURL() 会生成 data:application/octet-stream;base64,。只保留字节、不保留类型的存储和导出系统会把所有东西都这样标记。有些 API 把每个附件都声明为 octet-stream。于是依赖标签的查看器拒绝显示文件,下载时也得不到有用的扩展名。
字节本身通常就能说明格式:大多数格式都以固定的签名开头,工具会检查其中 60 多种。有少数签名是多种格式共用的,这时工具会往文件里多看一些:
| 开头字节 | Base64 开头 | 可能是 | 工具如何区分 |
|---|---|---|---|
PK 03 04 | UEsDB | ZIP、DOCX、XLSX、PPTX、EPUB、ODT、ODS、JAR、APK | 条目名称:word/、xl/、ppt/、mimetype 条目、AndroidManifest.xml、META-INF/MANIFEST.MF |
RIFF | UklGR | WebP、WAV、AVI | 第 8 个字节处的四个字母 |
第 4 个字节处为 ftyp | AAAA,例如 AAAAIGZ0eXB | MP4、M4A、MOV、3GP、HEIC、AVIF | 第 8 到 11 个字节处的品牌标识(brand) |
OggS | T2dnUw | Ogg Vorbis、Opus、Theora 视频 | 第一页中的编解码器头 |
1A 45 DF A3 | GkXfo | WebM、MKV | webm 文档类型 |
D0 CF 11 E0 | 0M8R4KGxGuE | DOC、XLS、PPT、Outlook MSG、受密码保护的 Office 文件 | 无法区分,显示为“DOC/XLS/MSG (OLE)” |
完整的签名列表见 常见 Base64 前缀。
如果 data URI 声明了类型而内容与之不符,会有一条提示,例如“data URI 声明为 application/octet-stream,但内容看起来是 PDF。”,并采用检测到的类型。只有在检测结果不够可靠时,也就是字节看起来像纯文本或未知二进制数据时,才以声明的类型为准。
Base64 套 Base64、URL 编码和 gzip
经过多个系统流转的数据经常被包了不止一层。解码后,工具会检查结果是否还有一层,并提供 再次解码:
| 提示 | 发生了什么 |
|---|---|
| “解码后的数据本身又是 Base64 文本(内部:PDF)。” | 被编码了两次,通常是两层代码都“为了保险”各编码了一次 |
| “解码后的数据是 URL 编码的 Base64” | Base64 先为了放进 URL 做了百分号编码(%2B、%2F、%3D),然后又被编码了一次 |
| “解码后的数据是 data: URI。” | 有人把整个 data:… 字符串编码了,而不是只编码其中的数据 |
| “数据经过 gzip 压缩:解压后 817 B(PDF)。” | 为节省空间在编码前做了压缩,在日志和消息队列中很常见;zlib 同样能识别 |
再次解码 会把内层数据放进输入框并解码;返回 则退回一层,最多记住 20 步。gzip 和 zlib 的提示只会在工具真正解压数据之后出现,适用于不超过 16 MB 的结果。gzip 预览还会显示文件头中保存的原始文件名和修改时间,并提供 保存解压结果 来保存内容。如果载荷是文本,gzip Base64 解码器 用起来更直接。
用正确的扩展名保存
Windows 和 macOS 根据扩展名选择打开文件的程序,所以保存为 decoded.bin 的 PDF 看起来像是坏了,尽管每个字节都没错。在你手动输入之前,扩展名 和 MIME 类型 字段会跟随检测结果:
- 文件名取自 data URI 中的
name=或filename=参数,或者取自你打开的文本文件名,并去掉.txt或.b64后缀:report.pdf.b64.txt会保存为report.pdf。 - 如果你知道某个 OLE 文件是电子表格,在 扩展名 中填
xls;工具无法区分 DOC、XLS 和 MSG。 - 你填写的 MIME 类型 也会让预览按该类型重新渲染。如果工具显示“二进制”而你认为是音频,填入
audio/ogg后它会尝试用音频播放器播放。 - MIME 类型只影响下载和 复制为 data URI;磁盘上的文件没有 MIME 类型,只有字节和文件名。
预览会显示什么
每个结果都会列出类型、MIME 类型、扩展名、大小和 SHA-256 哈希,并提供 显示 hex 转储 查看前 512 个字节。对于未知的二进制数据,hex 转储默认就是展开的。根据类型不同:
| 类型 | 预览 |
|---|---|
| 图片 | 图片本身及其像素尺寸;HEIC、TIFF 和 JPEG XL 通常会显示“无法显示”的提示,因为大多数浏览器没有相应的解码器。见 Base64 转图片。 |
| 浏览器的 PDF 查看器、版本、页数、标题。见 Base64 转 PDF。 | |
| 音频和视频 | 播放器,以及时长和视频尺寸 |
| 字体 | 用解码出的字体显示的可编辑示例文本,以及字体族、样式和字形数 |
| ZIP、DOCX、XLSX、PPTX、EPUB | 条目列表,每个文件都有 查看 和 保存;Office 文件和电子书还会显示文档文本。见 Base64 转 ZIP。 |
| 文本 | 字符集、行数、格式化后的 JSON、CSV 表格、XML 根元素、沙箱中的 HTML |
| 证书和密钥 | 指向 证书解码器 的链接 |
在代码中识别 Base64 的 MIME 类型
24 个 Base64 字符解码后是 18 个字节,足以识别常见的签名。以下代码适用于浏览器和 Node.js 16 及以上版本:
function sniffMime(b64) {
const head = b64.replace(/^data:[^,]*,/, "").replace(/\s+/g, "").slice(0, 24)
.replace(/-/g, "+").replace(/_/g, "/");
const b = Uint8Array.from(atob(head), (c) => c.charCodeAt(0));
const str = (start, len) => String.fromCharCode(...b.subarray(start, start + len));
if (str(0, 5) === "%PDF-") return "application/pdf";
if (str(0, 8) === "\x89PNG\r\n\x1a\n") return "image/png";
if (b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff) return "image/jpeg";
if (str(0, 4) === "GIF8") return "image/gif";
if (str(0, 4) === "RIFF" && str(8, 4) === "WEBP") return "image/webp";
if (str(0, 4) === "RIFF" && str(8, 4) === "WAVE") return "audio/wav";
if (str(4, 4) === "ftyp") return "video/mp4"; // also M4A, MOV, HEIC: see bytes 8-11
if (str(0, 4) === "PK\x03\x04") return "application/zip"; // also DOCX, XLSX, PPTX
if (b[0] === 0x1f && b[1] === 0x8b) return "application/gzip";
if (str(0, 3) === "ID3" || (b[0] === 0xff && (b[1] & 0xe6) === 0xe2)) return "audio/mpeg";
return "application/octet-stream";
}
sniffMime("data:application/octet-stream;base64,JVBERi0xLjcKJeLjz9MK"); // "application/pdf"
在命令行中,file 可以从标准输入读取解码后的字节:
base64 -d payload.b64 | file -b --mime-type -
对于 PDF,它会输出 application/pdf。如果改用 OpenSSL 解码,单行字符串要加 -A。不加的话,当这一行没有结尾换行符或者太长(OpenSSL 3.5 中为 1,024 个字符及以上)时,openssl base64 -d 会悄无声息地什么也不输出。更多内容见 JavaScript 中的 Base64 和 Bash 中的 Base64。
常见问题
怎么获取 Base64 字符串的 MIME 类型?
解码开头的几个字节,与已知的文件签名比对:JVBERi0 解码后是 %PDF-,iVBORw0KGgo 解码后是 PNG 签名。本页对 60 多种格式做了这件事,页面中的 JavaScript 函数则能在你自己的代码里覆盖常见格式。
提示“cannot display the file as application/octet-stream”是什么意思?
application/octet-stream 是“类型未知的字节”的通用标签,只看标签的查看器因此无从判断。把同一个字符串粘贴到这里:工具检查的是内容而不是标签,扩展名和 MIME 类型都会自动填好。
识别不出类型怎么办?
这时预览会显示“二进制”,并给出前 512 个字节的 hex 转储。如果你知道格式,下载前填好扩展名和 MIME 类型即可;MIME 类型还会切换预览方式,例如填 audio/ogg 后工具会尝试播放这些字节。
最大能解码多大的文件?
没有固定上限,取决于设备的内存。Base64 超过约 50 MB 时,页面在解码过程中会短暂停顿;文件超过 32 MB 时 复制为 data URI 会被禁用。
文件会被上传到什么地方吗?
不会。解码、类型识别和预览都在你的浏览器中运行,页面的内容安全策略使页面无法发出网络请求,Cloudflare 的浏览量统计除外。