Kodowanie Base64 w Java — Przykłady java.util.Base64

·Java Security & API Engineer·Sprawdzono przezPavel Novak·Opublikowano

Użyj darmowego Koder Base64 Online bezpośrednio w przeglądarce — bez instalacji.

Wypróbuj Koder Base64 Online online →

Za każdym razem, gdy konfiguruję nagłówek HTTP Basic Auth, osadzam certyfikat w sekretach Kubernetes lub przesyłam dane binarne przez JSON API, pierwszy krok jest zawsze ten sam: zakodować Base64 surowe bajty do łańcucha bezpiecznego dla ASCII. Java ułatwia to zadanie dzięki java.util.Base64, standardowemu API dostępnemu od Java 8, które zastąpiło wycofany sun.misc.BASE64Encoder. Jeśli potrzebujesz jednorazowego kodowania bez pisania kodu, Base64 Encoder ToolDeck zrobi to natychmiastowo w przeglądarce. Ten przewodnik obejmuje Base64.getEncoder(), getUrlEncoder(), getMimeEncoder(), kodowanie plików, strumieniowanie za pomocą wrap(OutputStream), a także błędy, które wpadają nawet doświadczonym programistom Java. Wszystkie przykłady kompilują się na Java 8 do Java 21+.

  • Base64.getEncoder().encodeToString(bytes) to standardowy jednowierszowiec — wbudowany w JDK od Java 8, niezmieniony w Java 17 i 21.
  • Zawsze przekazuj StandardCharsets.UTF_8 do String.getBytes() przed kodowaniem — pominięcie tego powoduje użycie domyślnego kodowania platformy, które różni się między JVM-ami.
  • getUrlEncoder() tworzy wynik bezpieczny dla URL (- zamiast +, _ zamiast /), a withoutPadding() usuwa końcowe znaki =.
  • getMimeEncoder() wstawia łamanie wierszy co 76 znaków — wymagane przez formaty email (MIME) i certyfikaty PEM.
  • W przypadku dużych plików użyj Base64.getEncoder().wrap(OutputStream) do strumieniowania bez ładowania całego pliku do pamięci.

Czym jest kodowanie Base64?

Base64 konwertuje dowolne dane binarne na łańcuch składający się z 64 drukowalnych znaków ASCII: A-Z, a-z, 0-9, + oraz /. Każde 3 bajty wejściowe dają dokładnie 4 znaki Base64. Jeśli długość wejścia nie jest wielokrotnością 3, dołączany jest jeden lub dwa znaki dopełnienia =. Zakodowany wynik jest zawsze o około 33% większy niż oryginalne dane.

Base64 to nie szyfrowanie. Każdy posiadający zakodowany łańcuch może go zdekodować. Jego celem jest bezpieczeństwo transportu: nagłówki HTTP, ładunki JSON, dokumenty XML i treść wiadomości email to protokoły tekstowe, które nie mogą przenosić surowych bajtów binarnych bez uszkodzenia danych. Typowe zastosowania w Javie obejmują HTTP Basic Authentication, osadzanie certyfikatów PEM, przechowywanie danych binarnych w kolumnach tekstowych bazy danych oraz budowanie segmentów tokenów JWT.

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

Base64.getEncoder().encodeToString() — Standardowe API

java.util.Base64 zostało wprowadzone w Java 8 jako oficjalny zamiennik sun.misc.BASE64Encoder. Klasa udostępnia trzy statyczne metody fabryczne — każda zwraca instancję zagnieżdżonej klasy Base64.Encoder — obejmując trzy warianty Base64 zdefiniowane w RFC 4648. Żadna biblioteka zewnętrzna nie jest potrzebna. Żadna zależność Maven. Wystarczy zaimportować i wywołać.

Minimalny przykład — kodowanie łańcucha

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
    }
}

Kluczowy krok, który większość programistów Java pomija przy pierwszym podejściu: String musi być skonwertowany do byte[] przed kodowaniem. Base64 operuje na bajtach, nie na znakach. encodeToString() przyjmuje byte[] i zwraca Base64 String bezpośrednio. Jeśli potrzebujesz zakodowanego wyniku jako bajtów, użyj encode(byte[]) — zwraca byte[] zakodowanych znaków Base64 w ASCII, przydatne przy bezpośrednim zapisie do OutputStream lub budowaniu ramek protokołu binarnego.

HTTP Basic Auth — Najczęstszy przypadek użycia

HTTP Basic Authentication to prawdopodobnie najczęstszy powód, dla którego programiści Java sięgają po kodowanie Base64. Specyfikacja (RFC 7617) wymaga, aby łańcuch danych uwierzytelniających username:password był zakodowany Base64 i umieszczony w nagłówku Authorization. Widziałem to zrobione niepoprawnie więcej razy, niż jestem w stanie zliczyć — zazwyczaj przez zapomnienie separatora dwukropka lub kodowanie komponentów osobno.

Java — nagłówek HTTP Basic Auth
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
    }
}

Pełny cykl — kodowanie i dekodowanie

Java 8+ — pełny cykl kodowania i dekodowania
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";

        // Kodowanie
        String encoded = Base64.getEncoder()
            .encodeToString(original.getBytes(StandardCharsets.UTF_8));
        System.out.println(encoded);
        // WC1Db3JyZWxhdGlvbi1JRDogcmVxXzhhNGYyYzkxLWU3YjMtNGQ1Ni05MDEyLTNmN2E4YjljMGQxZQ==

        // Dekodowanie
        byte[] decodedBytes = Base64.getDecoder().decode(encoded);
        String decoded = new String(decodedBytes, StandardCharsets.UTF_8);

        System.out.println(original.equals(decoded));  // true
    }
}
Uwaga:API java.util.Base64 jest identyczne od Java 8 przez Java 17 do Java 21. Podczas aktualizacji JDK nie jest potrzebna żadna migracja. Ten sam kod kompiluje się i działa na każdej wersji od Java 8.

Kodowanie danych innych niż String — byte[], UUID i znaczniki czasu

Kodowanie Base64 w Javie zawsze zaczyna się od byte[]. Łańcuchy konwertuje się przez getBytes(StandardCharsets.UTF_8), ale inne typy wymagają najpierw kroku konwersji. UUID, znaczniki czasu i identyfikatory numeryczne muszą być zserializowane do reprezentacji łańcuchowej lub bajtowej, zanim będzie można je zakodować Base64.

UUID — kodowanie jako reprezentacja łańcuchowa

Java — kodowanie UUID w Base64
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

Kompaktowy UUID — kodowanie surowych 16 bajtów

Jeśli chcesz uzyskać krótszy zakodowany wynik, wyodrębnij 128 bitów UUID jako 16 surowych bajtów zamiast konwertować do jego 36-znakowej postaci łańcuchowej. Wynik Base64 skraca się z 48 znaków do 24.

Java — kompaktowe kodowanie UUID
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 znaki wobec 48 dla podejścia łańcuchowego

Znacznik czasu i mieszany ładunek

Java — kodowanie ładunku podobnego do JSON ze znacznikiem czasu
import java.time.Instant;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// Symulacja ładunku w stylu 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, bez dopełnienia)
Ostrzeżenie:Nie wywołuj toString() na byte[] oczekując jego zawartości — da ci to hash tożsamości tablicy, np. [B@6d06d69c. Użyj new String(bytes, StandardCharsets.UTF_8) lub przekaż tablicę bajtów bezpośrednio do encodeToString().

Dokumentacja metod Base64.Encoder

Klasa java.util.Base64 udostępnia trzy metody fabryczne, każda zwracająca Base64.Encoder skonfigurowany dla konkretnego wariantu. Instancje kodera są bezpieczne wątkowo i bezstanowe — utwórz je raz i używaj wielokrotnie.

Metoda
Typ
Opis
getEncoder()
Base64.Encoder
Zwraca podstawowy koder RFC 4648 używający standardowego alfabetu (A-Z, a-z, 0-9, +, /)
getUrlEncoder()
Base64.Encoder
Zwraca koder używający alfabetu bezpiecznego dla URL (- zamiast +, _ zamiast /)
getMimeEncoder()
Base64.Encoder
Zwraca koder MIME wstawiający łamanie wierszy \r\n co 76 znaków
getMimeEncoder(lineLength, lineSeparator)
Base64.Encoder
Koder MIME z własną długością wiersza i sekwencją separatora
encoder.withoutPadding()
Base64.Encoder
Zwraca koder pomijający końcowe znaki dopełnienia =
encoder.encode(byte[])
byte[]
Koduje tablicę bajtów, zwraca zakodowaną tablicę bajtów
encoder.encodeToString(byte[])
String
Koduje tablicę bajtów, zwraca zakodowany String bezpośrednio
encoder.wrap(OutputStream)
OutputStream
Opakowuje OutputStream do strumieniowego kodowania Base64

Base64.getUrlEncoder() — Kodowanie bezpieczne dla URL

Koder URL-safe używa alternatywnego alfabetu, gdzie + staje się - a / staje się _, zgodnie z RFC 4648, sekcja 5. Ma to znaczenie wszędzie tam, gdzie łańcuch Base64 pojawia się w parametrze zapytania URL, nazwie pliku lub wartości ciasteczka — standardowe znaki Base64 kolidują z separatorami URL i zastrzeżonymi znakami systemu plików.

Java — kodowanie Base64 bezpieczne dla URL
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);

// Standardowy koder — zawiera + i / które psują URL-e
String standard = Base64.getEncoder().encodeToString(data);
System.out.println(standard);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s/c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw==

// Koder URL-safe — bezpieczny dla parametrów zapytania i nazw plików
String urlSafe = Base64.getUrlEncoder().encodeToString(data);
System.out.println(urlSafe);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw==

// URL-safe bez dopełnienia — dla JWT i zwartych tokenów
String noPadding = Base64.getUrlEncoder().withoutPadding().encodeToString(data);
System.out.println(noPadding);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw

Wariant withoutPadding() usuwa końcowe znaki =. Specyfikacje JWT wymagają URL-safe Base64 bez dopełnienia dla segmentów nagłówka i ładunku, dlatego getUrlEncoder().withoutPadding() to dokładnie to wywołanie, którego potrzebujesz przy ręcznym tworzeniu lub modyfikowaniu tokenów JWT.

Uwaga:Metoda withoutPadding() zwraca nową instancję kodera — nie modyfikuje oryginału. Obie mogą być przypisane do pól static final i bezpiecznie ponownie używane w wielu wątkach.

Kodowanie z pliku i odpowiedzi API

Dwa najczęstsze rzeczywiste scenariusze kodowania Base64 w Javie: odczytanie pliku binarnego z dysku (certyfikaty, obrazy, pakiety konfiguracyjne) oraz kodowanie danych otrzymanych z odpowiedzi HTTP.

Kodowanie pliku do Base64

Java — kodowanie pliku
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("Oryginał: %d bajtów%n", fileBytes.length);
            System.out.printf("Zakodowany:  %d znaków%n", encoded.length());

            // Zapisz zakodowaną zawartość do pliku tekstowego
            Files.writeString(
                Path.of("certs/server.pem.b64"),
                encoded
            );
        } catch (java.io.IOException e) {
            System.err.println("Błąd odczytu pliku: " + e.getMessage());
        }
    }
}

Kodowanie treści odpowiedzi API

Java 11+ — kodowanie odpowiedzi HTTP
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("Zakodowano %d bajtów → %d znaków%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("Żądanie nie powiodło się: " + e.getMessage());
        }
    }
}

Krótka uwaga przed sekcją o CLI: jeśli wystarczy ci wkleić plik lub odpowiedź API i uzyskać wynik Base64 bez pisania kodu, online Base64 Encoder obsługuje zarówno wejście tekstowe, jak i binarne.

Kodowanie Base64 z wiersza poleceń

Czasem wystarczy zakodować łańcuch lub plik z terminala — bez projektu Java, bez IDE, bez kroku budowania. Większość systemów Unix dostarcza polecenie base64, a jeśli masz zainstalowane JDK, możesz użyć jshell dla podejścia natywnego dla Javy.

Bash — kodowanie Base64 z wiersza poleceń
# macOS / Linux — kodowanie łańcucha
echo -n "deploy-bot:sk_prod_9f2a7c4e" | base64
# ZGVwbG95LWJvdDpza19wcm9kXzlmMmE3YzRl

# Kodowanie pliku
base64 < certs/server.pem > certs/server.pem.b64

# Użycie jshell (JDK 9+)
echo 'System.out.println(java.util.Base64.getEncoder().encodeToString("deploy-bot:sk_prod_9f2a7c4e".getBytes()))' | jshell -

# Użycie java bezpośrednio z jedną linią
java -e 'System.out.println(java.util.Base64.getEncoder().encodeToString(args[0].getBytes()))' "my-secret"
# Uwaga: java -e wymaga JDK 23+ (JEP 477)

Podejście z jshell jest szczególnie przydatne, gdy chcesz zweryfikować, że twój kod Java produkuje ten sam wynik co narzędzie Unix, lub gdy debugujesz rozbieżność między tym, co twoja usługa wysyła, a czego oczekuje odbiorca. Mam do tego alias w shellu.

Uwaga:Na macOS polecenie base64 używa -D do dekodowania. Na Linux (GNU coreutils) używa -d. Zachowanie przy kodowaniu jest identyczne na obu. Flaga -w 0 na Linux wyłącza zawijanie wierszy w wynikach, co zazwyczaj jest pożądane przy przekierowaniu do innych poleceń.

Apache Commons Codec — Wysokowydajna alternatywa

W większości aplikacji java.util.Base64 jest wystarczająco szybki. Ale jeśli przetwarzasz miliony operacji kodowania w ciasnej pętli — pomyśl o potokach ingestion logów lub brokerach wiadomości o wysokiej przepustowości — warto przeprowadzić benchmark z Apache Commons Codec. Istnieje od dawna przed Java 8 i zapewnia sprawdzoną alternatywę z nieco inną powierzchnią 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);

// Standardowe kodowanie
String encoded = Base64.encodeBase64String(telemetryPayload);

// Kodowanie URL-safe
String urlSafe = Base64.encodeBase64URLSafeString(telemetryPayload);

// Sprawdzenie, czy łańcuch jest poprawnym Base64
boolean valid = Base64.isBase64(encoded);
System.out.println(valid);  // true

Apache Commons Codec dostarcza też Base64OutputStream i Base64InputStream do scenariuszy strumieniowych oraz metodę walidacji, której brakuje w koderze JDK. Jeśli Commons Codec jest już w twoim drzewie zależności (jest dostarczany z wieloma projektami Apache), nie ma powodu, by go nie używać.

Guava BaseEncoding

Biblioteka Google Guava zawiera BaseEncoding, które zapewnia płynne API dla Base64 z konfigurowalnymi separatorami wierszy, kontrolą dopełnienia oraz obsługą zarówno standardowych, jak i bezpiecznych dla URL alfabetów. API jest czytelne, ale dodawanie Guavy (ok. 3 MB) tylko do kodowania Base64 to przesada. Jeśli Guava jest już w twoim projekcie dla kolekcji lub narzędzi do buforowania, API kodowania jest miłym bonusem.

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);

// Standardowy Base64
String standard = BaseEncoding.base64().encode(webhookPayload);

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

// Bez dopełnienia
String noPad = BaseEncoding.base64Url().omitPadding().encode(webhookPayload);

// Z separatorami wierszy (styl PEM)
String wrapped = BaseEncoding.base64()
    .withSeparator("\n", 64)
    .encode(webhookPayload);

Base64.getMimeEncoder() — Wyniki z łamaniem wierszy MIME i PEM

Koder MIME wstawia łamanie wierszy \r\n co 76 znaków, zgodnie ze specyfikacją MIME (RFC 2045). Certyfikaty PEM, załączniki S/MIME do poczty i niektóre starsze API oczekują tego formatu. Standardowy koder i koder URL-safe produkują pojedynczą nieprzerwana linię — jeśli przekażesz ich wynik do systemu oczekującego Base64 z łamaniem wierszy, może to po cichu zawieść lub odrzucić dane.

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

// Symulacja treści certyfikatu PEM
byte[] certData = new byte[256];  // W praktyce odczytaj z pliku .der
new java.security.SecureRandom().nextBytes(certData);

// Domyślny koder MIME — 76 znaków na wiersz, separator \r\n
String mimeEncoded = Base64.getMimeEncoder().encodeToString(certData);
System.out.println(mimeEncoded);
// QYx2K3p8Xg7JmN1R+wFkLd...  (76 znaków)
// Ht5Bv9CzAq0PnSjYl8WxUe...  (76 znaków)
// ...

// Własny koder MIME — 64 znaki na wiersz (standard PEM), separator \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-----");
Ostrzeżenie:Nie używaj getMimeEncoder() dla tokenów JWT, nagłówków HTTP ani parametrów URL. Łamanie wierszy uszkodzi dane w tych kontekstach. Zamiast tego użyj getEncoder() lub getUrlEncoder().

Strumieniowanie dużych plików z Base64.getEncoder().wrap()

Ładowanie całego pliku do byte[] za pomocą Files.readAllBytes() działa dla małych plików, ale dla wszystkiego powyżej 50-100 MB ryzykujesz OutOfMemoryError. JDK dostarcza Base64.getEncoder().wrap(OutputStream), który zwraca OutputStream kodujący dane w locie podczas zapisu. Zakodowane bajty przepływają do strumienia bazowego bez buforowania całego wejścia.

Java — strumieniowe kodowanie Base64
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("Przesłano strumieniowo %d bajtów przez koder Base64%n", totalBytes);
        }
        // Zamknięcie base64Out automatycznie zapisuje końcowe bajty dopełnienia
    }
}

Blok try-with-resources obsługuje opróżnianie bufora i zamykanie. Jeden szczegół, który często sprawia kłopoty: końcowe dopełnienie Base64 jest zapisywane dopiero po zamknięciu opakowującego OutputStream. Jeśli zapomnisz go zamknąć (lub zamkniesz tylko zewnętrzny strumień), ostatnie kilka znaków zakodowanego wyniku może być brakujących.

Strumieniowanie do gniazda sieciowego

Metoda wrap() działa z dowolnym OutputStream — plikiem wyjściowym, gniazdem sieciowym, treścią odpowiedzi HTTP, a nawet ByteArrayOutputStream. Oto przykład zapisujący zakodowane dane Base64 bezpośrednio do bufora w pamięci, co jest przydatne do testów jednostkowych lub budowania ładunków przesyłanych przez HTTP:

Java — strumieniowanie do 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)) {
    // Zapis danych w kawałkach — symulacja odczytu ze strumienia
    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=

// Weryfikacja pełnego cyklu
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
Uwaga:Rozmiar bufora w przykładzie strumieniowym (8192 bajtów) nie jest przypadkowy. Odpowiada domyślnemu rozmiarowi bufora używanemu przez BufferedInputStream i stanowi dobry kompromis między zużyciem pamięci a narzutem wywołań systemowych. Mniejsze bufory zwiększają liczbę wywołań odczytu/zapisu; większe marnują pamięć bez znaczącej poprawy przepustowości.

Bezpieczne wątkowo instancje kodera — przechowuj i używaj wielokrotnie

Base64.Encoder zwracany przez metody fabryczne jest niezmienny i bezpieczny wątkowo. Wywoływanie Base64.getEncoder() przy każdej operacji kodowania tworzy za każdym razem nowy obiekt. JVM prawdopodobnie to zoptymalizuje, ale przechowywanie kodera w polu static final wyraża intencję i unika zbędnych alokacji na gorących ścieżkach.

Java — wielokrotnie używane instancje kodera
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class TokenService {
    // Utwórz raz, używaj wszędzie — bezpieczny wątkowo
    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);
    }
}

Ten wzorzec jest szczególnie przydatny w usługach Spring Boot, gdzie klasa narzędziowa obsługuje kodowanie w wielu kontrolerach lub metodach serwisów. Wywołanie withoutPadding() zwraca nową instancję kodera, więc możesz przechowywać warianty z dopełnieniem i bez dopełnienia jako osobne pola. Każde wywołanie encodeToString() lub encode() jest bezstanowe — żadna synchronizacja nie jest potrzebna, żaden współdzielony stan mutowalny.

Typowe błędy

Wywołanie getBytes() bez podania charset

Problem: String.getBytes() bez argumentu charset używa domyślnego kodowania platformy, które wynosi windows-1252 na Windows, UTF-8 na większości systemów Linux i różni się na macOS. Ten sam kod produkuje różne wyniki Base64 na różnych maszynach.

Rozwiązanie: Zawsze jawnie przekazuj StandardCharsets.UTF_8.

Before · Java
After · Java
String text = "Ключ доступа: prod-east";
byte[] bytes = text.getBytes();  // domyślne platformy — nieprzewidywalne
String encoded = Base64.getEncoder().encodeToString(bytes);
String text = "Ключ доступа: prod-east";
byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
String encoded = Base64.getEncoder().encodeToString(bytes);
Używanie standardowego kodera dla parametrów URL

Problem: Base64.getEncoder() produkuje znaki + i /. Umieszczone w łańcuchu zapytania URL, + jest interpretowany jako spacja, a / jako separator ścieżki, co po cichu uszkadza wartość po stronie odbierającej.

Rozwiązanie: Używaj Base64.getUrlEncoder() dla każdej wartości, która pojawi się w URL.

Before · Java
After · Java
// Token w parametrze zapytania URL — zostanie uszkodzony
String token = Base64.getEncoder()
    .encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;
// Kodowanie URL-safe — bez znaków + ani /
String token = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;
Dekodowanie z użyciem niewłaściwego wariantu kodera

Problem: Kodowanie za pomocą getUrlEncoder() i dekodowanie za pomocą getDecoder() (lub odwrotnie) rzuca IllegalArgumentException, ponieważ - i _ nie są poprawne w standardowym alfabecie Base64, a + i / nie są poprawne w alfabecie URL-safe.

Rozwiązanie: Zawsze dekoduj dopasowanym dekoderem: getUrlDecoder() dla URL-safe, getDecoder() dla standardowego.

Before · Java
After · Java
String encoded = Base64.getUrlEncoder()
    .encodeToString(data);
// Później...
byte[] decoded = Base64.getDecoder()  // ZŁY dekoder
    .decode(encoded);
// IllegalArgumentException jeśli encoded zawiera - lub _
String encoded = Base64.getUrlEncoder()
    .encodeToString(data);
// Później...
byte[] decoded = Base64.getUrlDecoder()  // pasujący dekoder
    .decode(encoded);
Niezamknięcie OutputStream z wrap()

Problem: Koder strumieniowy buforuje do 2 bajtów wejściowych oczekując na pełną grupę 3-bajtową. Jeśli nie zamkniesz opakowującego OutputStream, ostatnie 1-4 znaki Base64 (łącznie z dopełnieniem) nigdy nie zostaną zapisane.

Rozwiązanie: Używaj try-with-resources lub wywołaj close() jawnie na opakowanym strumieniu przed odczytem wyniku.

Before · Java
After · Java
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream b64os = Base64.getEncoder().wrap(baos);
b64os.write(data);
// baos.toString() jest NIEKOMPLETNE — brakuje końcowych bajtów
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (OutputStream b64os = Base64.getEncoder().wrap(baos)) {
    b64os.write(data);
}  // close() zapisuje końcowe dopełnienie
String encoded = baos.toString();  // kompletne

Metody kodowania Base64 — Porównanie

Metoda
URL-Safe
Strumieniowanie
Łamanie wierszy
Typy niestandardowe
Wymaga instalacji
Base64.getEncoder()
✓ (wrap)
Nie (JDK 8+)
Base64.getUrlEncoder()
✓ (wrap)
Nie (JDK 8+)
Base64.getMimeEncoder()
✓ (wrap)
✓ (76 znaków)
Nie (JDK 8+)
Apache Commons Codec
Zależność Maven
Guava BaseEncoding
✓ (konfigurowalne)
Zależność Maven
jcmd / CLI base64
✓ (pipe)
N/A
Instalacja systemowa

W większości projektów: java.util.Base64 to właściwy wybór. Zero zależności, wbudowany w JDK, bezpieczny wątkowo i obsługuje wszystkie trzy warianty RFC 4648. Po Apache Commons Codec sięgaj tylko wtedy, gdy jest już w twoim classpath i potrzebujesz metody walidacji isBase64() lub strumieniowego Base64OutputStream. BaseEncoding z Guavy jest rozsądną opcją, jeśli twój projekt już zależy od Guavy, ale dodawanie zależności 3 MB tylko dla Base64 jest trudne do uzasadnienia.

Trzy scenariusze, trzy wybory: standardowy serwis webowy potrzebujący Basic Auth lub kodowania JWT? Zostań przy JDK. Starszy projekt ciągnący Commons Codec przez Spring lub Apache HTTP Client? Używaj go — nie ma powodu, by mieć dwie biblioteki Base64 w classpath. Projekt używający Guavy do buforowania i kolekcji? Używaj BaseEncoding dla jego czystego płynnego API. Nigdy nie dodawaj biblioteki tylko dla kodowania Base64 — wersja JDK jest wystarczająco dobra od 2014 roku.

Jeśli chcesz szybko zweryfikować zakodowany wynik bez uruchamiania kodu Java, wklej go do Base64 Encoder aby potwierdzić, że wynik odpowiada temu, co produkuje twój kod.

Często zadawane pytania

Jak zakodować String w Base64 w Javie?

Najpierw przekonwertuj łańcuch na bajty za pomocą getBytes(StandardCharsets.UTF_8), a następnie przekaż tablicę bajtów do Base64.getEncoder().encodeToString(). Zawsze podawaj UTF-8 jawnie — wywołanie getBytes() bez argumentu charset używa domyślnego kodowania platformy, które różni się między systemami operacyjnymi i konfiguracjami 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

Jaka jest różnica między Base64.getEncoder() a Base64.getUrlEncoder()?

Obie metody kodują do Base64, ale getUrlEncoder() używa alfabetu bezpiecznego dla URL zdefiniowanego w RFC 4648, sekcja 5. Zastępuje + przez - i / przez _, dzięki czemu wynik może pojawić się w URL-ach i nazwach plików bez kodowania procentowego. Standardowy koder używa + i /, które kolidują z parametrami zapytania URL i segmentami ścieżki.

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
// (tu to samo, ale z + → - i / → _ gdy te znaki się pojawią)

Czy java.util.Base64 jest taki sam w Java 8 i Java 17?

Tak. API java.util.Base64 nie zmieniło się od czasu wprowadzenia w Java 8. Klasa, jej zagnieżdżone klasy Encoder i Decoder oraz wszystkie metody fabryczne (getEncoder, getUrlEncoder, getMimeEncoder) są identyczne w Java 8, 11, 17 i 21. Podczas aktualizacji JDK nie są potrzebne żadne zmiany w kodzie.

Java
// Ten kod kompiluje się i działa identycznie na Java 8 do 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==

Jak zakodować plik do Base64 w Javie?

Wczytaj plik do tablicy bajtów za pomocą Files.readAllBytes(Path) i przekaż ją do Base64.getEncoder().encodeToString(). W przypadku dużych plików, których nie należy w całości ładować do pamięci, użyj Base64.getEncoder().wrap(OutputStream), aby strumieniować zakodowany wynik.

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);

Dlaczego sun.misc.BASE64Encoder został wycofany?

sun.misc.BASE64Encoder była wewnętrzną klasą JDK, która nigdy nie była częścią publicznego API. Znajdowała się w pakiecie sun.misc, przed używaniem którego Oracle wyraźnie ostrzegał. Java 8 wprowadziła java.util.Base64 jako oficjalną, publiczną i obsługiwaną alternatywę. Od Java 9 i systemu modułów dostęp do klas sun.misc generuje ostrzeżenia lub błędy w zależności od konfiguracji JDK.

Java
// Stary sposób — NIE używać, usunięty w nowszych JDK
// import sun.misc.BASE64Encoder;
// String encoded = new BASE64Encoder().encode(data);

// Właściwy sposób od Java 8
import java.util.Base64;
String encoded = Base64.getEncoder().encodeToString(data);

Jak wykonać pełny cykl kodowania i dekodowania Base64 w Javie?

Koduj za pomocą Base64.getEncoder().encodeToString(bytes) i dekoduj za pomocą Base64.getDecoder().decode(encodedString). Przekonwertuj zdekodowaną tablicę bajtów z powrotem na String używając new String(bytes, StandardCharsets.UTF_8). Cykl zachowuje oryginalne dane dokładnie — o ile użyjesz tego samego charset zarówno dla getBytes(), jak i new String().

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

// Kodowanie
String original = "session_token=eyJhbGciOiJSUzI1NiJ9";
byte[] originalBytes = original.getBytes(StandardCharsets.UTF_8);
String encoded = Base64.getEncoder().encodeToString(originalBytes);

// Dekodowanie
byte[] decodedBytes = Base64.getDecoder().decode(encoded);
String decoded = new String(decodedBytes, StandardCharsets.UTF_8);

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

Powiązane narzędzia

  • Base64 DecoderDekoduj łańcuchy Base64 z powrotem do ich oryginalnej postaci tekstowej lub binarnej — operacja odwrotna do kodowania.
  • URL EncoderKoduj łańcuchy procentowo do bezpiecznego użycia w URL-ach — inne niż kodowanie URL-safe Base64, ale często używane razem.
  • JWT DecoderSprawdzaj tokeny JWT, których segmenty nagłówka i ładunku są zakodowanymi Base64url JSON-ami — dekoduj bez biblioteki.
  • JSON FormatterFormatuj ładunki JSON przed kodowaniem Base64 lub po nim — przydatne przy debugowaniu integracji API.
Dostępne również w: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 NovakRecenzent techniczny

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.