For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/proposal-arraybuffer-base64.md.
  • 简体中文
  • Uint8Array to/from Base64 S4

    中文标题:Uint8Array 与 Base64 之间的转换

    提案概览
    提案速览

    该提案添加了 Uint8Array.prototype.toBase64()toHex(),以及静态方法 fromBase64()fromHex(),用于在二进制数据和 base64 或十六进制字符串之间进行转换。它还引入了 setFromBase64/setFromHex 用于写入现有数组,并提供选项来处理字母表、最后块处理和填充。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    Uint8Array 与 base64 和 hex 之间的转换

    base64 是一种将任意二进制数据表示为 ASCII 的常见方式。JavaScript 有 Uint8Array 来处理二进制数据,但没有内置机制将这些数据编码为 base64,也没有机制将 base64 数据转换为对应的 Uint8Array。本提案旨在解决这个问题。它还添加了在十六进制字符串和 Uint8Array 之间进行转换的方法。

    它目前处于 TC39 流程 的第 4 阶段:它已完整地包含在标准中。任何进一步的更改都需要通过 常规流程 在单独的提案中进行。此仓库已存档。

    playground 上试用。

    规范文本可在 此处 获得,test262 测试在 此 PR 中。

    实现者可能对 开源 simdutf 库 感兴趣,该库提供了 base64 解码器的快速实现,当未指定任何选项调用 Uint8Array.fromBase64(string) 时,其行为与之匹配(包括处理空白)。截至撰写本文时,它仅适用于 latin1 字符串,但 utf16 版本 可能即将推出

    基本 API

    let arr = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);
    console.log(arr.toBase64());
    // 'SGVsbG8gV29ybGQ='
    console.log(arr.toHex());
    // '48656c6c6f20576f726c64'
    let string = 'SGVsbG8gV29ybGQ=';
    console.log(Uint8Array.fromBase64(string));
    // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100])
    
    string = '48656c6c6f20576f726c64';
    console.log(Uint8Array.fromHex(string));
    // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100])

    这将添加 Uint8Array.prototype.toBase64/Uint8Array.prototype.toHexUint8Array.fromBase64/Uint8Array.fromHex 方法。如果传入的字符串没有正确编码,后者会抛出异常。

    Base64 选项

    在选项包参数中提供了额外的选项:

    • alphabet:允许将字母表指定为 base64base64url

    • lastChunkHandling:回想一下,base64 解码一次处理 4 个字符的块,但输入可能有一些字符不能均匀地分成 4 个字符的块。此选项决定应如何处理最后的字符块。三个选项是 "loose"(默认),它将块视为具有任何必要的 = 填充(但如果不可能,则抛出异常,即恰好有一个多余字符);"strict",它强制块恰好有 4 个字符(计算 = 填充),并且 溢出位 为 0;以及 "stop-before-partial",除非最后的块恰好有 4 个字符,否则在最后的块之前停止解码。

    • omitPadding:编码时,是否包含 = 填充。默认为 false,即包含填充。

    hex 方法不接受任何选项。

    写入现有的 Uint8Array

    Uint8Array.prototype.setFromBase64 方法允许写入现有的 Uint8Array。类似于 TextEncoder encodeInto 方法,它返回一个 { read, written } 对。

    let target = new Uint8Array(8);
    let { read, written } = target.setFromBase64('Zm9vYmFy');
    assert.deepStrictEqual([...target], [102, 111, 111, 98, 97, 114, 0, 0]);
    assert.deepStrictEqual({ read, written }, { read: 8, written: 6 });

    此方法接受一个可选的最终选项包,选项与上述相同。

    encodeInto 一样,不显式支持写入目标数组的指定偏移量,但您可以通过创建子数组来实现。

    Uint8Array.prototype.setFromHex 除了十六进制外完全相同。

    流式处理

    没有显式的流式处理支持。但是,在此 API 之上,在用户空间中相对容易高效地实现,并支持与底层函数相同的所有选项。

    常见问题解答

    标准、其他语言和现有 JavaScript 库中的 base64 实现之间存在哪些差异?

    我有一 整页关于此的页面,包含表格、脚注等。变异的空间相对较小,但语言和库设法探索了几乎所有的空间。

    总而言之,base64 编码器可能在以下方面有所不同:

    • 标准或 URL 安全字母表
    • 输出中是否包含 =
    • 是否在特定数量的字符后添加换行符

    解码器可能在以下方面有所不同:

    • 标准或 URL 安全字母表
    • 输入中是否需要 =,以及如何处理格式错误的填充(例如额外的 =
    • 是否对非零填充位失败
    • 行长度是否必须有限
    • 如何处理非 base64 字母表的字符(有时仅对子集进行特殊处理,例如空白)

    支持哪些字母表?

    对于 base64,您可以指定 base64base64url 用于编码器和解码器。

    对于 hex,小写和大写字符(包括在同一字符串中混合)都可以成功解码。输出始终为小写。

    如何处理额外的填充位?

    如果输入数据的长度不是 3 字节的倍数,则编码时,最后的 1 或 2 个字节将使用 2 或 3 个 base64 字符进行编码。由于每个 base64 字符是 6 位,这意味着您将使用 12 或 18 位来表示 8 或 16 位,这意味着您有额外的 4 或 2 位不编码任何内容。

    根据 RFC,解码器可以拒绝填充位非零的输入字符串。此处,除非指定了 lastChunkHandling: "strict",否则非零填充位会被静默忽略。

    如何处理空白?

    编码器不输出空白。hex 解码器不允许空白作为输入。base64 解码器允许字符串中的任何位置出现 ASCII 空白

    如何处理其他字符?

    任何其他字符的存在都会导致异常。

    为什么这些是同步的?

    实际上,我遇到的大多数 base64 编码的数据大约有几百字节(例如 SSH 密钥),可以极其快速地编码和解码。我认为,要求使用 Promise 来处理此类数据将是一种遗憾,尤其是考虑到目前人们使用的替代方案似乎都是同步的。

    为什么只支持这些编码?

    虽然还存在其他字符串编码,但没有一个像这两种一样常用。

    请参阅问题 #7#8#11

    为什么不直接使用 atobbtoa

    这些方法接受和消耗字符串,而不是在字符串和 Uint8Array 之间进行转换。

    为什么不使用 TextEncoder?

    base64 不是文本编码格式;不涉及 码点。因此,尽管符合 TextEncoder/TextDecoder 的类型签名,但 base64 编码和解码在概念上不适合那些 API 去做。

    这也是之前 讨论 中达成的共识。

    如果我只想编码 ArrayBuffer 的一部分怎么办?

    Uint8Array 可以是底层缓冲区的部分视图,因此您可以创建这样的视图并在其上调用 .toBase64