Datei hochladen
  1. base64hub
  2. Base64 im Code
  3. Java
Code

Base64 in Java

Seit Java 8 beherrscht java.util.Base64 Standard-, URL-sicheres und MIME-Base64, einschließlich Streaming. Alle Ausgaben unten stammen von Java 21.

Einen String kodieren und dekodieren

java.util.Base64 arbeitet mit Bytes. Wandeln Sie Strings mit einem expliziten Zeichensatz um, denn getBytes() ohne Argumente verwendet den Plattformstandard, und der war vor Java 18 nicht immer UTF-8.

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

String enc = Base64.getEncoder()
        .encodeToString("héllo wörld".getBytes(StandardCharsets.UTF_8));
System.out.println(enc);   // aMOpbGxvIHfDtnJsZA==

String dec = new String(Base64.getDecoder().decode(enc), StandardCharsets.UTF_8);
System.out.println(dec);   // héllo wörld

Instanzen von Base64.Encoder und Base64.Decoder sind threadsicher, Sie können sie also in einem static final-Feld halten.

URL-sicheres Base64 mit und ohne Padding

getUrlEncoder() verwendet - und _. Padding ist standardmäßig aktiv; withoutPadding() liefert einen neuen Encoder, der es weglässt:

byte[] d = "<<???>>".getBytes(StandardCharsets.UTF_8);

Base64.getUrlEncoder().encodeToString(d);                   // PDw_Pz8-Pg==
Base64.getUrlEncoder().withoutPadding().encodeToString(d);  // PDw_Pz8-Pg

new String(Base64.getUrlDecoder().decode("PDw_Pz8-Pg"), StandardCharsets.UTF_8);
// <<???>>

Die Decoder akzeptieren Eingaben mit und ohne Padding, auch getDecoder().decode("aGk") funktioniert also und liefert hi. JWT-Segmente sind Base64URL ohne Padding; wann Sie was verwenden, steht unter Base64 vs. Base64URL.

MIME-Encoder und -Decoder

getMimeEncoder() schreibt Zeilen mit 76 Zeichen, getrennt durch \r\n, wie RFC 2045 es verlangt. Nach der letzten Zeile fügt er keinen Zeilenumbruch an.

String mime = Base64.getMimeEncoder().encodeToString("x".repeat(60).getBytes());
// eHh4eHh4...eHh4  (76 chars) + "\r\n" + "eHh4"

Base64.getMimeEncoder(64, "\n".getBytes());   // PEM-style 64-char lines

Die Zeilenlänge wird auf ein Vielfaches von 4 abgerundet. getMimeDecoder() ist der tolerante Decoder: Er ignoriert Zeilentrenner und jedes andere Zeichen außerhalb des Alphabets.

Base64.getMimeDecoder().decode("aGVs\r\nbG8K!");   // bytes of "hello\n"

Der MIME-Base64-Encoder erzeugt dasselbe Format im Browser.

Eine Datei kodieren und dekodieren

Kleine Dateien:

import java.nio.file.*;

byte[] file = Files.readAllBytes(Path.of("hello.txt"));
System.out.println(Base64.getEncoder().encodeToString(file));   // aGVsbG8K

Files.write(Path.of("copy.txt"), Base64.getDecoder().decode("aGVsbG8K"));

Große Dateien mit wrap() streamen

Encoder.wrap(OutputStream) und Decoder.wrap(InputStream) kodieren und dekodieren im Durchlauf, der Speicherverbrauch bleibt also unabhängig von der Dateigröße konstant:

try (InputStream in = new FileInputStream("big.bin");
     OutputStream out = Base64.getEncoder().wrap(new FileOutputStream("big.b64"))) {
    in.transferTo(out);
}

try (InputStream in = Base64.getDecoder().wrap(new FileInputStream("big.b64"));
     OutputStream out = new FileOutputStream("big.out")) {
    in.transferTo(out);
}

Das Schließen des umhüllenden Streams ist wichtig: Der Encoder schreibt die letzte Gruppe und das Padding erst bei close(). Vergessen Sie es, fehlt die letzte Gruppe von bis zu vier Zeichen samt Padding. Bei einer 300-KB-Testdatei stimmte die Ausgabe exakt mit encodeToString überein, und der Roundtrip war byteidentisch. InputStream.transferTo braucht Java 9; unter Java 8 kopieren Sie mit einer Pufferschleife.

Validierung und Exceptions

Der Basis- und der URL-Decoder sind streng und werfen java.lang.IllegalArgumentException. Die Meldung sagt, was schiefging, Zeichen werden in Hex ausgegeben:

Eingabe für getDecoder()Meldung
PDw_Pz8-Pg==Illegal base64 character 5f
"aGVs\nbG8K"Illegal base64 character a
aGk=!!Input byte array has incorrect ending byte at 4
aGk==Input byte array has incorrect ending byte at 4
aInput byte[] should at least have 2 bytes for base64 bytes

Die Validierung ist also nur ein try/catch:

static boolean isBase64(String s) {
    try {
        Base64.getDecoder().decode(s);
        return true;
    } catch (IllegalArgumentException e) {
        return false;
    }
}

Eine Lücke gibt es: Der Decoder akzeptiert Padding-Bits ungleich null, aGl= wird also ohne Beanstandung zu hi dekodiert. Brauchen Sie ausschließlich kanonische Eingaben, kodieren Sie erneut und vergleichen. Der Base64-Validator zeigt, welches Zeichen das Problem ist, und Häufige Base64-Fehler erklärt jede Fehlerklasse.

Häufige Fallstricke

  • Plattform-Zeichensatz. "text".getBytes() und new String(bytes) verwenden den Standardzeichensatz. Unter Windows mit Java 17 oder älter war das meist Windows-1252, was Nicht-ASCII-Text zerstört. Java 18 hat UTF-8 zum Standard gemacht (JEP 400), aber StandardCharsets.UTF_8 mitzugeben kostet nichts.
  • Falscher Decoder für die Eingabe. URL-sichere Eingaben im Basis-Decoder ergeben Illegal base64 character 5f oder 2d. MIME-Eingaben ergeben Illegal base64 character a oder d.
  • encode() vs. encodeToString(). encode() liefert ein byte[] mit ASCII-Zeichen. Gibt man dieses Array aus, erscheint etwas wie [B@1b6d3586, kein Base64.
  • Den umhüllten Stream nicht schließen. Ohne close() ist die Ausgabe des Encoders abgeschnitten.
  • Annehmen, Base64 verstecke Daten. Das tut es nicht; siehe Kodierung vs. Verschlüsselung.

Versionshinweise

  • Java 8: java.util.Base64 eingeführt, mit Basis-, URL- und MIME-Variante, withoutPadding() und wrap().
  • Java 9: InputStream.transferTo, oben für Stream-Kopien verwendet.
  • Java 11: javax.xml.bind.DatatypeConverter.printBase64Binary ist mit der Entfernung von JAXB aus dem JDK verschwunden.
  • Java 18: UTF-8 wurde zum Standardzeichensatz.

Kotlin kann all das ebenfalls nutzen; es hat außerdem eine eigene Multiplattform-API, beschrieben unter Base64 in Kotlin.

Häufige Fragen

Was bedeutet „Illegal base64 character 5f“?

Die Zahl ist das fehlerhafte Zeichen in Hex. 5f ist _ und 2d ist -, Sie dekodieren also URL-sicheres Base64 mit getDecoder(). Verwenden Sie stattdessen getUrlDecoder(). a ist ein Zeilenumbruch und 20 ein Leerzeichen; nehmen Sie getMimeDecoder() oder entfernen Sie den Leerraum.

Sollte ich noch sun.misc.BASE64Encoder oder javax.xml.bind.DatatypeConverter verwenden?

Nein. sun.misc.BASE64Encoder ist eine interne API, die in aktuellen JDKs fehlt, und javax.xml.bind wurde mit Java 11 aus dem JDK entfernt. java.util.Base64 ersetzt beide.

Akzeptiert der Java-Decoder Base64 ohne Padding?

Ja. Base64.getDecoder().decode("aGk") liefert die Bytes von hi. Die Decoder akzeptieren fehlendes Padding, lehnen aber falsches Padding ab.

Wie kodiere ich Base64 unter Android?

Ab API-Level 26 steht java.util.Base64 zur Verfügung. Älterer Code verwendet android.util.Base64.encodeToString(bytes, Base64.NO_WRAP); ohne NO_WRAP fügt es Zeilenumbrüche ein.

Weiterlesen