Загрузить файл
  1. base64hub
  2. Статьи о Base64
  3. Рост размера
Справочник

Насколько Base64 увеличивает размер: точная формула

Каждые 3 байта превращаются в 4 символа, так что Base64 на треть больше исходных данных, плюс до 2 символов дополнения и переносы строк, если они есть. Точные числа посчитать несложно.

Формула

Для входных данных длиной n байт Base64 с дополнением (по умолчанию в RFC 4648) имеет длину ровно:

length = 4 × ceil(n / 3)

Без дополнения, как в Base64URL для JWT:

length = ceil(4n / 3)

Они различаются на число знаков =: 0, 1 или 2 в зависимости от n mod 3. Откуда они берутся, объясняет статья про дополнение.

В обратную сторону: строка Base64 с дополнением длиной L декодируется в:

bytes = 3 × L / 4 − (number of trailing "=")

Так что TWFu декодируется в 3 байта, TWE= в 2, а TQ== в 1. Перед подсчётом удалите пробелы и переносы строк. Калькулятор размера Base64 считает в обе стороны, с учётом переносов строк и префиксов data URI.

В коде:

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

Откуда берутся 33%

В байте 8 бит. Символ Base64 несёт 6 бит данных, потому что он один из 64 = 2⁶ символов, но хранится как 8-битный байт ASCII. Значит, каждый выходной байт содержит 6 полезных бит, и вывод должен быть в 8/6 = 4/3 раза больше входа. Это 33,3% сверху, и это жёсткий предел: ни одна реализация Base64 не сделает лучше, не отказавшись от алфавита. (Как перегруппировываются биты, пошагово показано в статье как работает Base64.)

На маленьких входных данных дополнение ухудшает соотношение, потому что вывод всегда идёт блоками по 4. Один байт превращается в 4 символа, то есть размер растёт на 300%. Уже на нескольких сотнях байтов дополнение становится пренебрежимо малым, и соотношение устанавливается на 4/3.

Есть и более плотные текстовые кодировки. Base85 хранит 4 байта в 5 символах (рост на 25%), у Base91 ещё чуть меньше. Их поддерживают реже, а в их алфавитах есть символы, которые кое-где создают проблемы. Сравнение есть в статье Base64, hex, Base32, Base58 и Base85.

Переносы строк: MIME, PEM и утилиты командной строки

Некоторые форматы разбивают Base64 на строки, и окончания строк тоже входят в размер.

ФорматДлина строкиОкончание строкиИтоговый рост
Обычный Base64 (RFC 4648)без переносовнет33,3%
Почта MIME (RFC 2045)76CRLF (2 байта)36,8%
GNU base64, Python encodebytes76LF (1 байт)35,1%
Сертификаты и ключи PEM64LF35,4%

Цифра для MIME получается из 4/3 × 78/76: каждые 76 символов Base64 приносят ещё 2 байта CRLF. При L = 4 × ceil(n / 3) размер с CRLF после каждой строки, включая последнюю, равен:

mime_length = L + 2 × ceil(L / 76)

Каждая полная строка из 76 символов содержит ровно 57 входных байт, поэтому кодировщики MIME обрабатывают данные кусками по 57 байт. О почте подробнее написано в статье Base64 в почте, а вывод с переносами выдаёт кодировщик MIME Base64.

Таблица размеров

Посчитано по формулам выше и сверено с модулем base64 из Python.

ВходBase64 с дополнениемБез дополненияMIME (76 + CRLF)Рост (с дополнением)
1 байт426300%
2 байта436100%
3 байта44633,3%
10 байт16141860%
57 байт76767833,3%
100 байт13613414036%
1000 байт13361334137233,6%
1 КиБ (1024)13681366140433,6%
1 МБ (10⁶)1 333 3361 333 3341 368 42433,3%
1 МиБ (1 048 576)1 398 1041 398 1021 434 89833,3%
10 МиБ13 981 01613 981 01414 348 93833,3%
25 МБ (25 × 10⁶)33 333 33633 333 33434 210 53033,3%

Последняя строка важна для почты. Ограничения размера в SMTP (расширение SIZE, RFC 1870) считают письмо в том виде, в каком оно передаётся, то есть вместе с кодированием, поэтому файл на 25 МБ при передаче занимает около 34,2 МБ и не пройдёт через лимит сервера в 25 МБ. Некоторые почтовые сервисы описывают свои лимиты по размеру вложения, так что уточните, как считает ваш.

Что даёт сжатие

Сжатие и Base64 сочетаются двумя способами, и порядок здесь важен.

Сжимайте до кодирования, когда контролируете обе стороны. Base64 от сжатых данных занимает те же 4/3, но от меньшего числа. Для текста лицензии GPL-3 (35 149 байт) мы измерили размеры через zlib в Node.js при уровне gzip 9:

ЦепочкаРазмер
Исходный текст35 149
Только Base6446 868
Base64, затем gzip17 465
gzip, затем Base6416 124
Только gzip12 091

Инструмент Gzip + Base64 выполняет цепочку «gzip, затем Base64» в браузере.

Сжатие при передаче возвращает большую часть потерь для двоичных данных. Если строка Base64 идёт внутри HTTP-ответа, сжатого gzip или Brotli, компрессор ужимает 6-битные символы почти обратно до 6 бит каждый. Для 1 МиБ случайных байтов Base64 вырос до 1 398 104 символов; после gzip получилось 1 053 023 байта (на 0,4% больше исходных данных), а Brotli довёл размер до 1 048 805. Те же данные с переносами строк MIME после gzip заняли 1 088 689 байт, так что CRLF стоят около 3,4% даже после сжатия.

С текстом иначе. Base64 разрушает повторы, на которые опираются компрессоры, поэтому текст в Base64 сжимается гораздо хуже, чем сам текст: 17 465 против 12 091 байта в таблице выше. В статье о производительности data URI есть замеры для PNG, JPEG, WOFF2 и SVG.

Base64 раздувает всё, что вы кладёте в URL, заголовок или cookie, а у всех трёх есть ограничения.

  • URL. RFC 9110 рекомендует отправителям и получателям поддерживать URI длиной не меньше 8000 октетов. Многие серверы по умолчанию останавливаются примерно там же: nginx выделяет под строку запроса буферы заголовков по 8 КБ, а LimitRequestLine в Apache по умолчанию равен 8190 байтам. Более длинные URL обычно падают с 414 URI Too Long. С Base64URL это место примерно под 6000 байт данных за вычетом остального URL.
  • Заголовки. Те же серверные буферы действуют на каждую строку заголовка, а это важно для длинных JWT в заголовках Authorization: Bearer ... и для больших учётных данных Basic Auth.
  • Cookie. RFC 6265 просит браузеры поддерживать не меньше 4096 байт на cookie, включая имя и атрибуты. Это примерно 3 КБ данных после кодирования в Base64.

Если полезная нагрузка в Base64 приближается к одному из этих лимитов, передавайте её в теле запроса или храните на сервере и передавайте идентификатор.

Посчитать размер Base64

Введите число байтов или вставьте строку, чтобы увидеть размер до и после кодирования, с переносами строк и без.

Калькулятор размера

Вопросы и ответы

Насколько Base64 больше исходного файла?

Примерно на 33,3% для всего, что длиннее нескольких байтов. С переносами строк MIME (76 символов плюс CRLF) рост составляет примерно 36,8%.

Как по строке Base64 посчитать исходный размер?

Возьмите длину без пробельных символов, умножьте на 3/4 и вычтите число знаков = в конце. Например, TWE= даёт 4 × 3/4 − 1 = 2 байта.

Почему 1 байт превращается в 4 символа?

С дополнением Base64 всегда выдаёт целые блоки по 4 символа. Один байт занимает 2 символа, а остальные 2 заняты знаками =, поэтому у крошечных входных данных относительный рост размера гораздо больше.

Можно ли сделать Base64 компактнее?

Сожмите данные перед кодированием, например через gzip, и отбросьте дополнение, если получатель это допускает. У самого Base64 соотношение фиксированное; есть и более плотные текстовые кодировки вроде Base85, но их поддерживают реже.

Читайте также