Base64-кодирование в Java — примеры java.util.Base64

·Java Security & API Engineer·ПровереноPavel Novak·Опубликовано

Используйте бесплатный Base64 Encode Online прямо в браузере — установка не требуется.

Попробовать Base64 Encode Online онлайн →

Каждый раз, когда я настраиваю заголовок HTTP Basic Auth, встраиваю сертификат в Kubernetes-секрет или передаю бинарные данные через JSON API, первый шаг один и тот же: закодировать исходные байты в Base64 — в ASCII-безопасную строку. В Java это делается просто с помощью java.util.Base64, стандартного API, доступного с Java 8, который пришёл на смену устаревшему sun.misc.BASE64Encoder. Если нужно быстро закодировать что-то без написания кода, Base64 Encoder на ToolDeck справится с этим мгновенно прямо в браузере. В этом руководстве рассмотрены Base64.getEncoder(), getUrlEncoder(), getMimeEncoder(), кодирование файлов, потоковая обработка с помощью wrap(OutputStream), а также типичные ошибки, на которые попадаются даже опытные Java-разработчики. Все примеры компилируются на Java 8 и выше, включая Java 21+.

  • Base64.getEncoder().encodeToString(bytes) — стандартная однострочная конструкция, встроенная в JDK с Java 8 и неизменная в Java 17 и 21.
  • Всегда передавайте StandardCharsets.UTF_8 в String.getBytes() перед кодированием — без указания кодировки используется платформенная, которая различается между JVM.
  • getUrlEncoder() формирует URL-safe вывод (- вместо +, _ вместо /), а withoutPadding() убирает символы = в конце.
  • getMimeEncoder() вставляет переносы строк каждые 76 символов — это требование форматов email (MIME) и PEM-сертификатов.
  • Для больших файлов используйте Base64.getEncoder().wrap(OutputStream) для потоковой обработки без загрузки всего файла в память.

Что такое Base64-кодирование?

Base64 преобразует произвольные бинарные данные в строку из 64 печатаемых ASCII-символов: A-Z, a-z, 0-9, + и /. Каждые 3 входных байта преобразуются ровно в 4 Base64-символа. Если длина входных данных не кратна 3, в конец добавляется один или два символа заполнения =. Закодированный результат примерно на 33% больше исходных данных.

Base64 — не шифрование. Любой, кто имеет закодированную строку, может её декодировать. Цель Base64 — безопасная передача данных: HTTP-заголовки, JSON-данные, XML-документы и тела email-сообщений являются текстовыми протоколами, которые не могут нести исходные бинарные байты без искажений. Типичные сценарии использования в Java: HTTP Basic Authentication, встраивание PEM-сертификатов, хранение бинарных данных в текстовых столбцах баз данных, формирование сегментов JWT-токенов.

Before · text
After · text
deploy-svc:sk_live_4eC39HqLyjWDarjtT1zdp7dc
ZGVwbG95LXN2Yzpza19saXZlXzRlQzM5SHFMeWpXRGFyanRUMXpkcDdkYw==

Base64.getEncoder().encodeToString() — стандартный API

java.util.Base64 появился в Java 8 как официальная замена sun.misc.BASE64Encoder. Класс предоставляет три статических фабричных метода, каждый из которых возвращает экземпляр вложенного класса Base64.Encoder — для трёх вариантов Base64, определённых в RFC 4648. Никакие сторонние библиотеки не нужны. Никаких Maven-зависимостей. Просто импорт и вызов.

Минимальный пример — кодирование строки

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class EncodeDemo {
    public static void main(String[] args) {
        String credentials = "monitoring-svc:9f2a7c4e-b1d8-4a3f";
        byte[] credentialBytes = credentials.getBytes(StandardCharsets.UTF_8);

        String encoded = Base64.getEncoder().encodeToString(credentialBytes);
        System.out.println(encoded);
        // bW9uaXRvcmluZy1zdmM6OWYyYTdjNGUtYjFkOC00YTNm
    }
}

Ключевой момент, который большинство Java-разработчиков упускает с первого раза: String необходимо преобразовать в byte[] перед кодированием. Base64 работает с байтами, а не с символами. encodeToString() принимает byte[] и возвращает Base64-строку String напрямую. Если нужен закодированный результат в виде байт, используйте encode(byte[]) — этот метод возвращает byte[] с ASCII-закодированными символами Base64, что удобно при записи напрямую в OutputStream или построении фреймов бинарных протоколов.

HTTP Basic Auth — самый распространённый сценарий

HTTP Basic Authentication — пожалуй, самая частая причина, по которой Java-разработчики обращаются к Base64-кодированию. Спецификация (RFC 7617) требует, чтобы строка учётных данных username:password была закодирована в Base64 и помещена в заголовок Authorization. Я видел это сделанным неправильно бессчётное количество раз — как правило, из-за забытого символа-разделителя двоеточия или раздельного кодирования компонентов.

Java — HTTP Basic Auth header
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class BasicAuthExample {
    public static void main(String[] args) throws Exception {
        String username = "metrics-exporter";
        String apiKey = "sk_live_4eC39HqLyjWDarjtT1zdp7dc";

        // username:password → Base64
        String credentials = username + ":" + apiKey;
        String authHeader = "Basic " + Base64.getEncoder()
            .encodeToString(credentials.getBytes(StandardCharsets.UTF_8));

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.example.com/v2/metrics"))
            .header("Authorization", authHeader)
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(response.statusCode());  // 200
    }
}

Round-trip — кодирование и декодирование

Java 8+ — encode and decode round-trip
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class RoundTrip {
    public static void main(String[] args) {
        String original = "X-Correlation-ID: req_8a4f2c91-e7b3-4d56-9012-3f7a8b9c0d1e";

        // Кодирование
        String encoded = Base64.getEncoder()
            .encodeToString(original.getBytes(StandardCharsets.UTF_8));
        System.out.println(encoded);
        // WC1Db3JyZWxhdGlvbi1JRDogcmVxXzhhNGYyYzkxLWU3YjMtNGQ1Ni05MDEyLTNmN2E4YjljMGQxZQ==

        // Декодирование
        byte[] decodedBytes = Base64.getDecoder().decode(encoded);
        String decoded = new String(decodedBytes, StandardCharsets.UTF_8);

        System.out.println(original.equals(decoded));  // true
    }
}
Примечание:API java.util.Base64 идентичен для Java 8, Java 17 и Java 21. При обновлении JDK никакой миграции не требуется. Один и тот же код компилируется и работает на любой версии начиная с Java 8.

Кодирование нестроковых данных — byte[], UUID и временны́е метки

Base64-кодирование в Java всегда начинается с byte[]. Строки преобразуются через getBytes(StandardCharsets.UTF_8), но для других типов сначала нужен шаг конверсии. UUID, временны́е метки и числовые идентификаторы необходимо сериализовать в строку или байтовое представление, прежде чем их можно будет закодировать в Base64.

UUID — кодирование через строковое представление

Java — Base64 encoding a UUID
import java.util.Base64;
import java.util.UUID;
import java.nio.charset.StandardCharsets;

UUID sessionId = UUID.fromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
String encoded = Base64.getEncoder()
    .encodeToString(sessionId.toString().getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);
// NmJhN2I4MTAtOWRhZC0xMWQxLTgwYjQtMDBjMDRmZDQzMGM4

Компактный UUID — кодирование сырых 16 байт

Если нужен более короткий результат, извлеките 128 бит UUID как 16 сырых байт, а не преобразуйте его в строку длиной 36 символов. Длина Base64-результата сократится с 48 до 24 символов.

Java — compact UUID encoding
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.UUID;

UUID eventId = UUID.fromString("550e8400-e29b-41d4-a716-446655440000");

ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
buffer.putLong(eventId.getMostSignificantBits());
buffer.putLong(eventId.getLeastSignificantBits());

String compact = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(buffer.array());
System.out.println(compact);
// VQ6EAOKbQdSnFkRmVUQAAA
// 22 символа против 48 при строковом подходе

Временна́я метка и составная нагрузка

Java — encoding a JSON-like payload with timestamp
import java.time.Instant;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// Имитация JWT-style payload
String payload = String.format(
    "{"sub":"usr_7b3c","iss":"auth.internal","iat":%d,"exp":%d}",
    Instant.now().getEpochSecond(),
    Instant.now().plusSeconds(3600).getEpochSecond()
);

String encoded = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(payload.getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);
// eyJzdWIiOiJ1c3JfN2IzYyIsImlzcyI6ImF1dGguaW50ZXJuYWwiLCJpYXQiOj... (URL-safe, без заполнения)
Предупреждение:Не вызывайте toString() на byte[], ожидая получить его содержимое — это даст хеш идентичности массива вида [B@6d06d69c. Используйте new String(bytes, StandardCharsets.UTF_8) или передавайте массив байт напрямую в encodeToString().

Справочник методов Base64.Encoder

Класс java.util.Base64 предоставляет три фабричных метода, каждый из которых возвращает Base64.Encoder настроенный под конкретный вариант. Экземпляры кодировщиков потокобезопасны и не имеют состояния — создайте их один раз и используйте повторно.

Метод
Тип
Описание
getEncoder()
Base64.Encoder
Возвращает стандартный кодировщик RFC 4648 с базовым алфавитом (A-Z, a-z, 0-9, +, /)
getUrlEncoder()
Base64.Encoder
Возвращает кодировщик с URL-безопасным алфавитом (- вместо +, _ вместо /)
getMimeEncoder()
Base64.Encoder
Возвращает MIME-кодировщик, вставляющий переносы строк \r\n каждые 76 символов
getMimeEncoder(lineLength, lineSeparator)
Base64.Encoder
MIME-кодировщик с настраиваемой длиной строки и разделителем
encoder.withoutPadding()
Base64.Encoder
Возвращает кодировщик, не добавляющий символы заполнения = в конце
encoder.encode(byte[])
byte[]
Кодирует массив байт, возвращает закодированный массив байт
encoder.encodeToString(byte[])
String
Кодирует массив байт, возвращает закодированную строку String
encoder.wrap(OutputStream)
OutputStream
Оборачивает OutputStream для потокового Base64-кодирования

Base64.getUrlEncoder() — URL-safe кодирование

URL-safe кодировщик использует альтернативный алфавит, где + заменяется на -, а / заменяется на _, как определено в RFC 4648, раздел 5. Это важно везде, где Base64-строка появляется в URL-параметре, имени файла или значении cookie — стандартные символы Base64 конфликтуют с разделителями URL и зарезервированными символами файловой системы.

Java — URL-safe Base64 encoding
import java.util.Base64;
import java.nio.charset.StandardCharsets;

String redirectUri = "https://app.internal/callback?state=auth_pending&nonce=9f2a7c";
byte[] data = redirectUri.getBytes(StandardCharsets.UTF_8);

// Стандартный кодировщик — содержит + и /, которые ломают URL
String standard = Base64.getEncoder().encodeToString(data);
System.out.println(standard);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s/c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw==

// URL-safe кодировщик — безопасен для параметров запроса и имён файлов
String urlSafe = Base64.getUrlEncoder().encodeToString(data);
System.out.println(urlSafe);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw==

// URL-safe без заполнения — для JWT и компактных токенов
String noPadding = Base64.getUrlEncoder().withoutPadding().encodeToString(data);
System.out.println(noPadding);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw

Вариант с withoutPadding() убирает символы = в конце строки. Спецификации JWT требуют URL-safe Base64 без заполнения для сегментов заголовка и payload, поэтому getUrlEncoder().withoutPadding() — именно тот вызов, который нужен при ручном формировании или обработке JWT-токенов.

Примечание:Метод withoutPadding() возвращает новый экземпляр кодировщика, не изменяя исходный. Оба могут быть сохранены в полях static final и безопасно переиспользоваться из разных потоков.

Кодирование файлов и ответов API

Два наиболее распространённых реальных сценария Base64-кодирования в Java: чтение бинарного файла с диска (сертификаты, изображения, конфигурационные пакеты) и кодирование данных, полученных в HTTP-ответе.

Кодирование файла в Base64

Java — encoding a file
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

public class FileEncoder {
    public static void main(String[] args) {
        try {
            byte[] fileBytes = Files.readAllBytes(Path.of("certs/server.pem"));
            String encoded = Base64.getEncoder().encodeToString(fileBytes);

            System.out.printf("Исходный: %d байт%n", fileBytes.length);
            System.out.printf("Закодированный:  %d символов%n", encoded.length());

            // Запись закодированного содержимого в текстовый файл
            Files.writeString(
                Path.of("certs/server.pem.b64"),
                encoded
            );
        } catch (java.io.IOException e) {
            System.err.println("Ошибка чтения файла: " + e.getMessage());
        }
    }
}

Кодирование тела ответа API

Java 11+ — encoding an HTTP response
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;

public class ApiEncoder {
    public static void main(String[] args) {
        try {
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.example.com/v2/reports/weekly.pdf"))
                .header("Authorization", "Bearer tok_8f2a9c3d")
                .build();

            HttpResponse<byte[]> response = client.send(
                request, HttpResponse.BodyHandlers.ofByteArray()
            );

            if (response.statusCode() == 200) {
                String encoded = Base64.getEncoder()
                    .encodeToString(response.body());
                System.out.printf("Закодировано %d байт → %d символов%n",
                    response.body().length, encoded.length());
            } else {
                System.err.printf("HTTP %d: %s%n",
                    response.statusCode(),
                    new String(response.body()));
            }
        } catch (Exception e) {
            System.err.println("Запрос не выполнен: " + e.getMessage());
        }
    }
}

Небольшое замечание перед разделом о CLI: если нужно просто вставить файл или ответ API и получить Base64-результат без написания кода, онлайн-кодировщик Base64 обрабатывает как текстовый, так и бинарный ввод.

Base64-кодирование из командной строки

Иногда нужно закодировать строку или файл прямо из терминала — без Java-проекта, без IDE, без сборки. На большинстве Unix-систем есть команда base64, а если установлен JDK, можно использовать jshell для Java-нативного подхода.

Bash — command-line Base64 encoding
# macOS / Linux — кодирование строки
echo -n "deploy-bot:sk_prod_9f2a7c4e" | base64
# ZGVwbG95LWJvdDpza19wcm9kXzlmMmE3YzRl

# Кодирование файла
base64 < certs/server.pem > certs/server.pem.b64

# Использование jshell (JDK 9+)
echo 'System.out.println(java.util.Base64.getEncoder().encodeToString("deploy-bot:sk_prod_9f2a7c4e".getBytes()))' | jshell -

# Использование java напрямую в однострочнике
java -e 'System.out.println(java.util.Base64.getEncoder().encodeToString(args[0].getBytes()))' "my-secret"
# Примечание: java -e требует JDK 23+ (JEP 477)

Подход с jshell особенно полезен, когда нужно убедиться, что ваш Java-код даёт тот же результат, что и Unix-утилита, или при отладке несоответствия между тем, что отправляет ваш сервис, и тем, что ожидает получатель. Я держу для этого shell-псевдоним.

Примечание:На macOS команда base64 использует флаг -D для декодирования. На Linux (GNU coreutils) используется -d. Поведение при кодировании идентично на обоих. Флаг -w 0 на Linux отключает перенос строк в выводе, что обычно и нужно при пайпинге в другие команды.

Apache Commons Codec — высокопроизводительная альтернатива

Для большинства приложений java.util.Base64 достаточно быстр. Но если вы обрабатываете миллионы операций кодирования в узком цикле — например, в пайплайнах приёма логов или высокопропускных брокерах сообщений — стоит сделать бенчмарк с Apache Commons Codec. Он существует ещё с времён до Java 8 и предлагает проверенную альтернативу с несколько иным API.

Java — Apache Commons Codec
// Maven: org.apache.commons:commons-codec:1.17.0
import org.apache.commons.codec.binary.Base64;
import java.nio.charset.StandardCharsets;

byte[] telemetryPayload = ("{"service":"metrics-collector","
    + ""host":"prod-east-07","
    + ""cpu_pct":72.4,"
    + ""mem_mb":3891,"
    + ""timestamp":1710523200}")
    .getBytes(StandardCharsets.UTF_8);

// Стандартное кодирование
String encoded = Base64.encodeBase64String(telemetryPayload);

// URL-safe кодирование
String urlSafe = Base64.encodeBase64URLSafeString(telemetryPayload);

// Проверка валидности Base64-строки
boolean valid = Base64.isBase64(encoded);
System.out.println(valid);  // true

Apache Commons Codec также предоставляет Base64OutputStream и Base64InputStream для потоковых сценариев, а также метод валидации, которого нет в JDK-кодировщике. Если Commons Codec уже есть в вашем дереве зависимостей (он входит во многие Apache-проекты), нет причин его не использовать.

Guava BaseEncoding

Библиотека Google Guava включает BaseEncoding с fluent API для Base64: настраиваемые разделители строк, управление заполнением и поддержка стандартного и URL-safe алфавитов. API читается легко, но добавлять Guava (около 3 МБ) только ради Base64-кодирования — излишество. Если Guava уже есть в проекте ради коллекций или утилит кеширования, API кодирования станет приятным бонусом.

Java — Guava BaseEncoding
// Maven: com.google.guava:guava:33.1.0-jre
import com.google.common.io.BaseEncoding;
import java.nio.charset.StandardCharsets;

byte[] webhookPayload = ("{"event":"deployment.completed","
    + ""repo":"payments-api","
    + ""sha":"a7f2c91e4b3d","
    + ""environment":"production"}")
    .getBytes(StandardCharsets.UTF_8);

// Стандартный Base64
String standard = BaseEncoding.base64().encode(webhookPayload);

// URL-safe
String urlSafe = BaseEncoding.base64Url().encode(webhookPayload);

// Без заполнения
String noPad = BaseEncoding.base64Url().omitPadding().encode(webhookPayload);

// С разделителями строк (PEM-стиль)
String wrapped = BaseEncoding.base64()
    .withSeparator("\n", 64)
    .encode(webhookPayload);

Base64.getMimeEncoder() — MIME и PEM с переносами строк

MIME-кодировщик вставляет переносы строк \r\n каждые 76 символов в соответствии со спецификацией MIME (RFC 2045). PEM-сертификаты, S/MIME-вложения в email и некоторые устаревшие API ожидают именно этот формат. Стандартный и URL-safe кодировщики формируют единую непрерывную строку — если передать их вывод системе, ожидающей Base64 с переносами строк, она может молча упасть или отклонить данные.

Java — MIME Base64 encoding
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// Имитация тела PEM-сертификата
byte[] certData = new byte[256];  // На практике — читать из .der-файла
new java.security.SecureRandom().nextBytes(certData);

// Стандартный MIME-кодировщик — 76 символов в строке, разделитель \r\n
String mimeEncoded = Base64.getMimeEncoder().encodeToString(certData);
System.out.println(mimeEncoded);
// QYx2K3p8Xg7JmN1R+wFkLd...  (76 символов)
// Ht5Bv9CzAq0PnSjYl8WxUe...  (76 символов)
// ...

// Настроенный MIME-кодировщик — 64 символа в строке (стандарт PEM), разделитель \n
Base64.Encoder pemEncoder = Base64.getMimeEncoder(64, new byte[]{'\n'});
String pemBody = pemEncoder.encodeToString(certData);
System.out.println("-----BEGIN CERTIFICATE-----");
System.out.println(pemBody);
System.out.println("-----END CERTIFICATE-----");
Предупреждение:Не используйте getMimeEncoder() для JWT-токенов, HTTP-заголовков или URL-параметров. Переносы строк испортят данные в этих контекстах. Используйте getEncoder() или getUrlEncoder().

Потоковая обработка больших файлов через Base64.getEncoder().wrap()

Загрузка целого файла в byte[] через Files.readAllBytes() подходит для небольших файлов, но для файлов свыше 50–100 МБ есть риск OutOfMemoryError. JDK предоставляет Base64.getEncoder().wrap(OutputStream), который возвращает OutputStream и кодирует данные на лету по мере записи. Закодированные байты передаются во вложенный поток без буферизации всего ввода.

Java — streaming Base64 encoding
import java.io.*;
import java.nio.file.*;
import java.util.Base64;

public class StreamingEncoder {
    public static void main(String[] args) throws IOException {
        Path inputPath = Path.of("backups/database-export.sql.gz");
        Path outputPath = Path.of("backups/database-export.sql.gz.b64");

        try (
            InputStream in = Files.newInputStream(inputPath);
            OutputStream fileOut = Files.newOutputStream(outputPath);
            OutputStream base64Out = Base64.getEncoder().wrap(fileOut)
        ) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            long totalBytes = 0;

            while ((bytesRead = in.read(buffer)) != -1) {
                base64Out.write(buffer, 0, bytesRead);
                totalBytes += bytesRead;
            }

            System.out.printf("Передано через Base64-кодировщик: %d байт%n", totalBytes);
        }
        // Закрытие base64Out автоматически сбрасывает финальные байты заполнения
    }
}

Блок try-with-resources берёт на себя сброс буфера и закрытие потоков. Один нюанс, который часто упускают: финальное Base64-заполнение записывается только при закрытии оборачивающего OutputStream. Если забыть его закрыть (или закрыть только внешний поток), последние несколько символов закодированного вывода будут отсутствовать.

Потоковая передача в сетевой сокет

Метод wrap() работает с любым OutputStream — файловым, сокетным, телом HTTP-ответа и даже ByteArrayOutputStream. Вот пример записи Base64-закодированных данных непосредственно во внутренний буфер — это удобно для юнит-тестирования или формирования полезной нагрузки для отправки по HTTP:

Java — streaming to ByteArrayOutputStream
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

try (OutputStream encoder = Base64.getEncoder().wrap(buffer)) {
    // Запись данных частями — имитация чтения из потока
    encoder.write("chunk-1:telemetry-data-".getBytes(StandardCharsets.UTF_8));
    encoder.write("chunk-2:more-payload-".getBytes(StandardCharsets.UTF_8));
    encoder.write("chunk-3:final-segment".getBytes(StandardCharsets.UTF_8));
}

String encoded = buffer.toString(StandardCharsets.UTF_8);
System.out.println(encoded);
// Y2h1bmstMTp0ZWxlbWV0cnktZGF0YS1jaHVuay0yOm1vcmUtcGF5bG9hZC1jaHVuay0zOmZpbmFsLXNlZ21lbnQ=

// Проверка round-trip
byte[] decoded = Base64.getDecoder().decode(encoded);
System.out.println(new String(decoded, StandardCharsets.UTF_8));
// chunk-1:telemetry-data-chunk-2:more-payload-chunk-3:final-segment
Примечание:Размер буфера в примере потоковой обработки (8192 байта) выбран не случайно. Он совпадает с размером буфера по умолчанию в BufferedInputStream и обеспечивает хороший баланс между потреблением памяти и накладными расходами на системные вызовы. Меньшие буферы увеличивают число операций чтения/записи; большие расходуют память без заметного прироста пропускной способности.

Потокобезопасные экземпляры кодировщика — хранение и переиспользование

Экземпляр Base64.Encoder, возвращаемый фабричными методами, неизменяем и потокобезопасен. Вызов Base64.getEncoder() при каждой операции кодирования каждый раз создаёт новый объект. JVM, вероятно, оптимизирует это, но хранение кодировщика в поле static final явно выражает намерение и избегает лишних аллокаций на горячих путях.

Java — reusable encoder instances
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class TokenService {
    // Создаём один раз, используем везде — потокобезопасно
    private static final Base64.Encoder STANDARD = Base64.getEncoder();
    private static final Base64.Encoder URL_SAFE = Base64.getUrlEncoder().withoutPadding();
    private static final Base64.Encoder MIME = Base64.getMimeEncoder();

    public static String encodeForHeader(String value) {
        return STANDARD.encodeToString(value.getBytes(StandardCharsets.UTF_8));
    }

    public static String encodeForUrl(byte[] data) {
        return URL_SAFE.encodeToString(data);
    }

    public static String encodeForEmail(byte[] attachment) {
        return MIME.encodeToString(attachment);
    }
}

Этот паттерн особенно полезен в Spring Boot-сервисах, где утилитный класс обслуживает несколько контроллеров или сервисных методов. Вызов withoutPadding() возвращает новый экземпляр кодировщика, поэтому можно хранить оба варианта — с заполнением и без — как отдельные поля. Каждый вызов encodeToString() или encode() не имеет состояния — синхронизация не нужна, разделяемого изменяемого состояния нет.

Типичные ошибки

Вызов getBytes() без указания кодировки

Проблема: String.getBytes() без аргумента-кодировки использует кодировку платформы по умолчанию: windows-1252 на Windows, UTF-8 на большинстве Linux-систем и варьируется на macOS. Один и тот же код на разных машинах даёт разный Base64-результат.

Решение: Всегда явно передавайте StandardCharsets.UTF_8.

Before · Java
After · Java
String text = "Ключ доступа: prod-east";
byte[] bytes = text.getBytes();  // платформенная кодировка — непредсказуемо
String encoded = Base64.getEncoder().encodeToString(bytes);
String text = "Ключ доступа: prod-east";
byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
String encoded = Base64.getEncoder().encodeToString(bytes);
Использование стандартного кодировщика для URL-параметров

Проблема: Base64.getEncoder() выводит символы + и /. В строке URL-запроса + интерпретируется как пробел, а / — как разделитель пути, что молча искажает значение на стороне получателя.

Решение: Используйте Base64.getUrlEncoder() для любого значения, которое будет помещено в URL.

Before · Java
After · Java
// Токен в URL-параметре — сломается
String token = Base64.getEncoder()
    .encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;
// URL-safe кодирование — без символов + и /
String token = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;
Декодирование с помощью несоответствующего кодировщика

Проблема: Кодирование через getUrlEncoder() и декодирование через getDecoder() (или наоборот) бросает IllegalArgumentException: символы - и _ не входят в стандартный алфавит Base64, а + и / — в URL-safe алфавит.

Решение: Всегда декодируйте соответствующим декодером: getUrlDecoder() для URL-safe, getDecoder() для стандартного.

Before · Java
After · Java
String encoded = Base64.getUrlEncoder()
    .encodeToString(data);
// Позднее...
byte[] decoded = Base64.getDecoder()  // НЕВЕРНЫЙ декодер
    .decode(encoded);
// IllegalArgumentException если encoded содержит - или _
String encoded = Base64.getUrlEncoder()
    .encodeToString(data);
// Позднее...
byte[] decoded = Base64.getUrlDecoder()  // подходящий декодер
    .decode(encoded);
Незакрытый OutputStream от wrap()

Проблема: Потоковый кодировщик буферизует до 2 входных байт в ожидании полной группы из 3 байт. Если не закрыть оборачивающий OutputStream, финальные 1–4 символа Base64 (включая заполнение) никогда не будут записаны.

Решение: Используйте try-with-resources или явно вызывайте close() на обёрнутом потоке перед чтением результата.

Before · Java
After · Java
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream b64os = Base64.getEncoder().wrap(baos);
b64os.write(data);
// baos.toString() НЕПОЛНЫЙ — отсутствуют финальные байты
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (OutputStream b64os = Base64.getEncoder().wrap(baos)) {
    b64os.write(data);
}  // close() сбрасывает финальное заполнение
String encoded = baos.toString();  // полный результат

Методы Base64-кодирования — сравнение

Метод
URL-Safe
Потоковый
Переносы строк
Произвольные типы
Требует установки
Base64.getEncoder()
✓ (wrap)
Нет (JDK 8+)
Base64.getUrlEncoder()
✓ (wrap)
Нет (JDK 8+)
Base64.getMimeEncoder()
✓ (wrap)
✓ (76 символов)
Нет (JDK 8+)
Apache Commons Codec
Maven-зависимость
Guava BaseEncoding
✓ (настраиваемые)
Maven-зависимость
jcmd / CLI base64
✓ (pipe)
N/A
Системная установка

Для большинства проектов: java.util.Base64 — правильный выбор. Никаких зависимостей, встроен в JDK, потокобезопасен и охватывает все три варианта RFC 4648. Обращайтесь к Apache Commons Codec только если он уже есть в вашем classpath и нужен метод валидации isBase64() или потоковый Base64OutputStream.BaseEncoding из Guava — разумный вариант если проект уже зависит от Guava, но добавлять 3 МБ зависимости только ради Base64 сложно оправдать.

Три сценария — три выбора: стандартный веб-сервис, которому нужен Basic Auth или JWT? Используйте JDK. Легаси-проект, уже подтягивающий Commons Codec через Spring или Apache HTTP Client? Используйте его — нет смысла держать в classpath две библиотеки Base64. Проект, использующий Guava для кеширования и коллекций? Используйте BaseEncoding с его чистым fluent API. Никогда не добавляйте библиотеку только ради Base64-кодирования — JDK-версия достаточно хороша с 2014 года.

Если нужно быстро проверить закодированный результат без запуска Java-кода, вставьте его в Base64 Encoder и убедитесь, что вывод совпадает с тем, что даёт ваш код.

Часто задаваемые вопросы

Как закодировать строку в Base64 в Java?

Сначала преобразуйте строку в байты с помощью getBytes(StandardCharsets.UTF_8), затем передайте массив байт в Base64.getEncoder().encodeToString(). Всегда явно указывайте UTF-8 — вызов getBytes() без аргумента кодировки использует кодировку платформы по умолчанию, которая варьируется между операционными системами и конфигурациями JVM.

Java
import java.util.Base64;
import java.nio.charset.StandardCharsets;

String payload = "grant_type=client_credentials&scope=read:metrics";
String encoded = Base64.getEncoder()
    .encodeToString(payload.getBytes(StandardCharsets.UTF_8));
// Z3JhbnRfdHlwZT1jbGllbnRfY3JlZGVudGlhbHMmc2NvcGU9cmVhZDptZXRyaWNz

В чём разница между Base64.getEncoder() и Base64.getUrlEncoder()?

Оба метода выполняют Base64-кодирование, но getUrlEncoder() использует URL-безопасный алфавит, определённый в RFC 4648, раздел 5. Он заменяет + на - и / на _, поэтому результат можно использовать в URL-адресах и именах файлов без percent-кодирования. Стандартный кодировщик использует + и /, которые конфликтуют с разделителями URL и сегментами пути.

Java
byte[] data = "subject=usr_7b3c&role=admin".getBytes(StandardCharsets.UTF_8);

String standard = Base64.getEncoder().encodeToString(data);
// c3ViamVjdD11c3JfN2IzYyZyb2xlPWFkbWlu

String urlSafe = Base64.getUrlEncoder().encodeToString(data);
// c3ViamVjdD11c3JfN2IzYyZyb2xlPWFkbWlu
// (здесь одинаково, но + → - и / → _ когда эти символы встречаются)

Одинаков ли java.util.Base64 в Java 8 и Java 17?

Да. API java.util.Base64 не менялся с момента появления в Java 8. Класс, вложенные классы Encoder и Decoder, а также все фабричные методы (getEncoder, getUrlEncoder, getMimeEncoder) идентичны в Java 8, 11, 17 и 21. При обновлении JDK никакой миграции или изменений кода не требуется.

Java
// Этот код компилируется и работает одинаково на Java 8 — Java 21+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

String encoded = Base64.getEncoder()
    .encodeToString("stable-api".getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);  // c3RhYmxlLWFwaQ==

Как закодировать файл в Base64 в Java?

Считайте файл в массив байт с помощью Files.readAllBytes(Path) и передайте его в Base64.getEncoder().encodeToString(). Для больших файлов, которые не следует загружать целиком в память, используйте Base64.getEncoder().wrap(OutputStream) для потокового кодирования.

Java
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

byte[] fileBytes = Files.readAllBytes(Path.of("config/tls-cert.pem"));
String encoded = Base64.getEncoder().encodeToString(fileBytes);

Почему sun.misc.BASE64Encoder устарел?

sun.misc.BASE64Encoder был внутренним классом JDK, никогда не входившим в публичный API. Он находился в пакете sun.misc, который Oracle явно не рекомендовал использовать. В Java 8 появился java.util.Base64 как официальная, публичная, поддерживаемая замена. Начиная с Java 9 и системы модулей, обращение к классам sun.misc приводит к предупреждениям или ошибкам в зависимости от конфигурации JDK.

Java
// Старый способ — НЕ использовать, удалён в современных JDK
// import sun.misc.BASE64Encoder;
// String encoded = new BASE64Encoder().encode(data);

// Правильный способ начиная с Java 8
import java.util.Base64;
String encoded = Base64.getEncoder().encodeToString(data);

Как выполнить round-trip Base64-кодирование и декодирование в Java?

Кодируйте с помощью Base64.getEncoder().encodeToString(bytes), декодируйте с помощью Base64.getDecoder().decode(encodedString). Преобразуйте декодированный массив байт обратно в строку через new String(bytes, StandardCharsets.UTF_8). Round-trip точно восстанавливает исходные данные — при условии, что для getBytes() и new String() используется одна и та же кодировка.

Java
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// Кодирование
String original = "session_token=eyJhbGciOiJSUzI1NiJ9";
byte[] originalBytes = original.getBytes(StandardCharsets.UTF_8);
String encoded = Base64.getEncoder().encodeToString(originalBytes);

// Декодирование
byte[] decodedBytes = Base64.getDecoder().decode(encoded);
String decoded = new String(decodedBytes, StandardCharsets.UTF_8);

System.out.println(original.equals(decoded));  // true

Связанные инструменты

  • Base64 DecoderДекодирует Base64-строки обратно в исходный текст или бинарные данные — операция, обратная кодированию.
  • URL EncoderPercent-кодирует строки для безопасного использования в URL — отличается от URL-safe Base64, но часто применяется рядом с ним.
  • JWT DecoderИнспектирует JWT-токены, заголовок и payload которых закодированы Base64url — декодирует без сторонних библиотек.
  • JSON FormatterФорматирует JSON-данные до или после Base64-кодирования — удобно при отладке интеграций с API.
Также доступно на:JavaScriptPython
AO
Aisha OseiJava Security & API Engineer

Aisha is a Java engineer specialising in application security, Spring Security, and API design. She has worked on identity and access management systems, OAuth 2.0 integrations, and microservice security at scale. She writes about secure Java coding practices, token validation, cryptographic utilities, and the Spring ecosystem from a security-first perspective.

PN
Pavel NovakТехнический рецензент

Pavel is a backend engineer with deep roots in the JVM ecosystem, working primarily with Java and Kotlin. He has extensive experience building data-intensive services and integrating third-party APIs at scale. He writes about modern Java features, the Jackson ecosystem, serialisation patterns, and practical approaches to keeping large codebases maintainable.