Кодування Base64 у Java — Приклади java.util.Base64

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

Використовуйте безкоштовний Base64 Encode Online прямо в браузері — без встановлення.

Спробувати Base64 Encode Online онлайн →

Щоразу, коли я налаштовую заголовок HTTP Basic Auth, вбудовую сертифікат у Kubernetes Secret або передаю бінарні дані через 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-безпечний вивід (- замість +, _ замість /) а withoutPadding() прибирає кінцеві символи =.
  • getMimeEncoder() вставляє переноси рядків кожні 76 символів — обов'язково для електронної пошти (MIME) та PEM-сертифікатів.
  • Для великих файлів використовуйте Base64.getEncoder().wrap(OutputStream) для потокової передачі без завантаження всього файлу в пам'ять.

Що таке кодування Base64?

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

Base64 — це не шифрування. Будь-хто, хто має закодований рядок, може його декодувати. Його призначення — безпека транспортування: HTTP-заголовки, JSON-навантаження, XML-документи та тіла електронних листів є текстовими протоколами, які не можуть передавати сирі бінарні байти без пошкодження. Типові випадки використання в 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
    }
}

Повний цикл — кодування і декодування

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-подібного навантаження
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, no padding)
Попередження:Не викликайте 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-безпечне кодування

URL-безпечний кодувальник використовує альтернативний алфавіт, де + стає - а / стає _, як визначено в 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-безпечний кодувальник — безпечний для параметрів запиту та імен файлів
String urlSafe = Base64.getUrlEncoder().encodeToString(data);
System.out.println(urlSafe);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw==

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

Варіант withoutPadding() прибирає кінцеві символи =. Специфікації JWT вимагають URL-безпечного Base64 без доповнення для сегментів заголовка та навантаження, тому 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("Original: %d bytes%n", fileBytes.length);
            System.out.printf("Encoded:  %d chars%n", encoded.length());

            // Запис закодованого вмісту у текстовий файл
            Files.writeString(
                Path.of("certs/server.pem.b64"),
                encoded
            );
        } catch (java.io.IOException e) {
            System.err.println("Failed to read file: " + 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("Encoded %d bytes → %d chars%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("Request failed: " + e.getMessage());
        }
    }
}

Коротка замітка перед розділом про CLI: якщо вам просто потрібно вставити файл або відповідь API і отримати вивід Base64 без написання коду, онлайн Base64 Encoder обробляє як текстовий, так і бінарний ввід.

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-безпечне кодування
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

Бібліотека Guava від Google включає BaseEncoding, що надає fluent API для Base64 з конфігурованими роздільниками рядків, керуванням доповненням та підтримкою стандартного і URL-безпечного алфавітів. 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-безпечний
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 електронної пошти та деякі застарілі API очікують саме цей формат. Стандартний і URL-безпечний кодувальники виробляють один нерозривний рядок — якщо передати їхній вивід системі, що очікує 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("Streamed %d bytes through Base64 encoder%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=

// Перевірка повного циклу
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-безпечне кодування — без символів + або /
String token = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;
Декодування за допомогою неправильного варіанту кодувальника

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

Рішення: Завжди декодуйте відповідним декодером: getUrlDecoder() для URL-безпечного, 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-безпечний
Потоковий
Переноси рядків
Власні типи
Потребує встановлення
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? Використовуйте його — немає причини мати дві бібліотеки Base64 у classpath. Проект з 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-encoding. Стандартний кодувальник використовує + та /, які конфліктують з параметрами запиту 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);

Як виконати повний цикл кодування і декодування Base64 у Java?

Кодуйте за допомогою Base64.getEncoder().encodeToString(bytes), а декодуйте за допомогою Base64.getDecoder().decode(encodedString). Перетворіть декодований масив байтів назад на рядок за допомогою new String(bytes, StandardCharsets.UTF_8). Повний цикл точно відтворює вихідні дані — за умови, що ви використовуєте одне й те саме кодування як у 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-безпечного кодування Base64, але часто використовується разом із ним.
  • JWT DecoderПеревіряйте JWT-токени, заголовок та сегменти корисного навантаження яких закодовані у Base64url JSON — декодуйте без бібліотек.
  • 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.