La fórmula
Para una entrada de n bytes, el Base64 con relleno (el predeterminado en el RFC 4648) mide exactamente:
length = 4 × ceil(n / 3)
Sin relleno, como en el Base64URL de los JWT, mide:
length = ceil(4n / 3)
La diferencia entre ambas es el número de signos =, que es 0, 1 o 2 según n mod 3. La guía del relleno explica de dónde salen.
En sentido contrario, una cadena Base64 con relleno de longitud L se decodifica en:
bytes = 3 × L / 4 − (number of trailing "=")
Así, TWFu son 3 bytes, TWE= son 2 y TQ== es 1. Quita los espacios en blanco y los saltos de línea antes de contar. La calculadora de tamaño Base64 hace las dos direcciones, incluidos los saltos de línea y los prefijos de data URI.
En código:
import base64, math, os
for n in [1, 2, 3, 100, 1000]:
data = os.urandom(n)
assert len(base64.b64encode(data)) == 4 * math.ceil(n / 3)
const b64Len = (n) => 4 * Math.ceil(n / 3);
const rawLen = (s) => (s.length * 3) / 4 - (s.endsWith("==") ? 2 : s.endsWith("=") ? 1 : 0);
b64Len(1000); // 1336
rawLen("TWE="); // 2
Por qué el aumento es del 33 %
Un byte tiene 8 bits. Un carácter Base64 lleva 6 bits de datos, porque es uno de 64 = 2⁶ símbolos, pero se guarda como un byte ASCII de 8 bits. Así que cada byte de salida contiene 6 bits útiles, y la salida tiene que medir 8/6 = 4/3 de la entrada. Eso es un 33,3 % más, y es un mínimo absoluto: ninguna implementación de Base64 puede hacerlo mejor sin abandonar el alfabeto. (Cómo se reagrupan los bits se muestra paso a paso en cómo funciona Base64.)
Con entradas pequeñas, el relleno empeora la proporción, porque la salida siempre va en bloques de 4. Un byte se convierte en 4 caracteres, un aumento del 300 %. A partir de unos cientos de bytes, el relleno es despreciable y la proporción se estabiliza en 4/3.
Existen codificaciones de texto más densas. Base85 guarda 4 bytes en 5 caracteres (un 25 % de aumento), y Base91 baja un poco más. Tienen menos soporte y sus alfabetos incluyen caracteres que dan problemas en algunos contextos. La comparación está en Base64 frente a hex, Base32, Base58, Base85.
Saltos de línea: MIME, PEM y herramientas de línea de comandos
Algunos formatos cortan el Base64 en líneas, y los finales de línea cuentan para el tamaño.
| Formato | Longitud de línea | Final de línea | Aumento total |
|---|---|---|---|
| Base64 sin más (RFC 4648) | sin cortes | ninguno | 33,3 % |
| Correo MIME (RFC 2045) | 76 | CRLF (2 bytes) | 36,8 % |
GNU base64, encodebytes de Python | 76 | LF (1 byte) | 35,1 % |
| Certificados y claves PEM | 64 | LF | 35,4 % |
La cifra de MIME sale de 4/3 × 78/76: cada 76 caracteres de Base64 traen 2 bytes más de CRLF. Con L = 4 × ceil(n / 3), el tamaño incluyendo un CRLF tras cada línea, también la última, es:
mime_length = L + 2 × ceil(L / 76)
Cada línea completa de 76 caracteres contiene exactamente 57 bytes de entrada, y por eso los codificadores MIME procesan los datos en bloques de 57 bytes. Más sobre el correo en Base64 en el correo electrónico; el codificador Base64 MIME genera la salida con cortes de línea.
Tabla de tamaños
Calculada con las fórmulas de arriba y comprobada con el módulo base64 de Python.
| Entrada | Base64 con relleno | Sin relleno | MIME (76 + CRLF) | Aumento (con relleno) |
|---|---|---|---|---|
| 1 byte | 4 | 2 | 6 | 300 % |
| 2 bytes | 4 | 3 | 6 | 100 % |
| 3 bytes | 4 | 4 | 6 | 33,3 % |
| 10 bytes | 16 | 14 | 18 | 60 % |
| 57 bytes | 76 | 76 | 78 | 33,3 % |
| 100 bytes | 136 | 134 | 140 | 36 % |
| 1000 bytes | 1336 | 1334 | 1372 | 33,6 % |
| 1 KiB (1024) | 1368 | 1366 | 1404 | 33,6 % |
| 1 MB (10⁶) | 1 333 336 | 1 333 334 | 1 368 424 | 33,3 % |
| 1 MiB (1 048 576) | 1 398 104 | 1 398 102 | 1 434 898 | 33,3 % |
| 10 MiB | 13 981 016 | 13 981 014 | 14 348 938 | 33,3 % |
| 25 MB (25 × 10⁶) | 33 333 336 | 33 333 334 | 34 210 530 | 33,3 % |
La última fila corresponde al correo. Los límites de tamaño de SMTP (la extensión SIZE, RFC 1870) cuentan el mensaje tal como se transmite, codificación incluida, así que un archivo de 25 MB se convierte en unos 34,2 MB en la transmisión y no pasará el límite de 25 MB de un servidor. Algunos proveedores expresan sus límites en función del adjunto, así que comprueba cómo cuenta el tuyo.
Qué hace la compresión
La compresión interactúa con Base64 de dos maneras, y el orden importa.
Comprime antes de codificar siempre que controles los dos extremos. El Base64 de unos datos comprimidos es 4/3 de un número más pequeño. Con el texto de la licencia GPL-3 (35 149 bytes) medimos con zlib de Node.js a nivel 9 de gzip:
| Proceso | Tamaño |
|---|---|
| Texto original | 35 149 |
| Solo Base64 | 46 868 |
| Base64 y después gzip | 17 465 |
| gzip y después Base64 | 16 124 |
| Solo gzip | 12 091 |
La herramienta Gzip + Base64 hace el proceso «gzip y después Base64» en el navegador.
La compresión en el transporte recupera casi todo el aumento con datos binarios. Si una cadena Base64 viaja dentro de una respuesta HTTP comprimida con gzip o Brotli, el compresor vuelve a acercar los caracteres de 6 bits a 6 bits cada uno. Con 1 MiB de bytes aleatorios, el Base64 creció hasta 1 398 104 caracteres; con gzip quedó en 1 053 023 bytes (un 0,4 % por encima de los datos originales) y Brotli lo dejó en 1 048 805. Los mismos datos con saltos de línea MIME quedaron en 1 088 689 con gzip, así que los CRLF cuestan alrededor de un 3,4 % incluso después de comprimir.
Con el texto es distinto. Base64 rompe las repeticiones de las que dependen los compresores, así que el texto en Base64 se comprime mucho peor que el propio texto: 17 465 frente a 12 091 bytes en la tabla de arriba. El artículo sobre el rendimiento de los data URI tiene mediciones para PNG, JPEG, WOFF2 y SVG.
Límites de URL, cabeceras y cookies
Base64 hincha todo lo que metas en una URL, una cabecera o una cookie, y las tres tienen límites.
- URL. El RFC 9110 recomienda que emisores y receptores admitan URI de al menos 8000 octetos. Muchos servidores se cortan cerca de esa cifra por defecto: nginx reserva búferes de cabecera de 8 KB para la línea de petición, y
LimitRequestLinede Apache vale 8190 bytes por defecto. Las URL más largas suelen fallar con414 URI Too Long. Con Base64URL eso deja sitio para unos 6000 bytes de datos, menos el resto de la URL. - Cabeceras. Los mismos búferes del servidor se aplican a cada línea de cabecera, algo importante con los JWT largos en cabeceras
Authorization: Bearer ...y con credenciales Basic Auth grandes. - Cookies. El RFC 6265 pide a los navegadores que admitan al menos 4096 bytes por cookie, incluidos el nombre y los atributos. Eso son unos 3 KB de datos una vez codificados en Base64.
Si un payload Base64 se acerca a alguno de estos límites, envíalo en el cuerpo de la petición, o guárdalo en el servidor y pasa un ID.
Introduce un número de bytes o pega una cadena para ver los tamaños codificado y decodificado, con o sin saltos de línea.
Preguntas frecuentes
¿Cuánto más ocupa Base64 que el archivo original?
Alrededor de un 33,3 % para cualquier cosa de más de unos pocos bytes. Con saltos de línea MIME (76 caracteres más CRLF), alrededor de un 36,8 %.
¿Cómo calculo el tamaño original a partir de una cadena Base64?
Toma la longitud sin espacios en blanco, multiplícala por 3/4 y resta el número de signos = del final. Por ejemplo, TWE= son 4 × 3/4 − 1 = 2 bytes.
¿Por qué una entrada de 1 byte produce 4 caracteres?
Cuando se usa relleno, Base64 siempre genera bloques completos de 4 caracteres. Un byte ocupa 2 caracteres y los otros 2 son =, así que las entradas muy pequeñas tienen un aumento relativo mucho mayor.
¿Puedo hacer que Base64 ocupe menos?
Comprime los datos antes de codificarlos, por ejemplo con gzip, y quita el relleno si el receptor lo permite. Base64 en sí tiene una proporción fija; existen codificaciones de texto más densas, como Base85, pero tienen menos soporte.