Charger un fichier
  1. base64hub
  2. Base64 dans le code
  3. Java
Code

Base64 en Java

Depuis Java 8, java.util.Base64 gère le Base64 standard, URL-safe et MIME, flux compris. Toutes les sorties ci-dessous proviennent de Java 21.

Encoder et décoder une chaîne

java.util.Base64 travaille sur des octets. Convertissez les chaînes avec un jeu de caractères explicite : sans argument, getBytes() utilise celui de la plateforme, qui n’était pas toujours UTF-8 avant Java 18.

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

Les instances de Base64.Encoder et Base64.Decoder sont thread-safe : vous pouvez les garder dans un champ static final.

Base64 URL-safe avec et sans remplissage

getUrlEncoder() utilise - et _. Le remplissage est activé par défaut ; withoutPadding() renvoie un nouvel encodeur qui l’omet :

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

Les décodeurs acceptent une entrée avec ou sans remplissage : getDecoder().decode("aGk") fonctionne aussi et renvoie hi. Les segments d’un JWT sont en Base64URL sans remplissage ; voir Base64 ou Base64URL pour savoir quand utiliser l’un ou l’autre.

Encodeur et décodeur MIME

getMimeEncoder() écrit des lignes de 76 caractères séparées par \r\n, comme l’exige la RFC 2045. Il n’ajoute pas de saut de ligne après la dernière ligne.

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

La longueur de ligne est arrondie au multiple de 4 inférieur. getMimeDecoder() est le décodeur tolérant : il ignore les séparateurs de ligne et tout autre caractère hors de l’alphabet.

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

L’encodeur Base64 MIME produit le même format dans le navigateur.

Encoder et décoder un fichier

Petits fichiers :

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

Gros fichiers en flux avec wrap()

Encoder.wrap(OutputStream) et Decoder.wrap(InputStream) encodent et décodent à la volée : la consommation mémoire reste constante, quelle que soit la taille du fichier.

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

Fermer le flux enveloppant est indispensable : l’encodeur écrit le dernier groupe et le remplissage au moment du close(). Si vous l’oubliez, il manque tout le dernier groupe, soit jusqu’à quatre caractères, remplissage compris. Sur un fichier de test de 300 Ko, la sortie correspondait exactement à encodeToString et l’aller-retour était identique à l’octet près. InputStream.transferTo demande Java 9 ; en Java 8, copiez avec une boucle et un tampon.

Validation et exceptions

Les décodeurs basic et URL sont stricts et lèvent java.lang.IllegalArgumentException. Le message indique ce qui ne va pas, avec les caractères affichés en hexadécimal :

Entrée de getDecoder()Message
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

La validation se résume donc à un try/catch :

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

Une lacune : le décodeur accepte les bits de remplissage non nuls, si bien que aGl= se décode en hi sans broncher. Si vous n’acceptez que des entrées canoniques, réencodez et comparez. Le validateur Base64 montre quel caractère pose problème, et les erreurs Base64 courantes expliquent chaque type d’échec.

Pièges courants

  • Le jeu de caractères de la plateforme. "text".getBytes() et new String(bytes) utilisent le jeu de caractères par défaut. Sous Windows avec Java 17 ou antérieur, c’était en général Windows-1252, ce qui casse le texte non ASCII. Java 18 a fait d’UTF-8 le défaut (JEP 400), mais passer StandardCharsets.UTF_8 ne coûte rien.
  • Le mauvais décodeur pour l’entrée. Une entrée URL-safe dans le décodeur basic donne Illegal base64 character 5f ou 2d. Une entrée MIME donne Illegal base64 character a ou d.
  • encode() ou encodeToString(). encode() renvoie un byte[] de caractères ASCII. Afficher ce tableau donne quelque chose comme [B@1b6d3586, pas du Base64.
  • Ne pas fermer le flux enveloppé. Sans close(), la sortie de l’encodeur est tronquée.
  • Croire que Base64 cache les données. Ce n’est pas le cas ; voir encodage ou chiffrement.

Notes de version

  • Java 8 : arrivée de java.util.Base64 avec les variantes basic, URL et MIME, withoutPadding() et wrap().
  • Java 9 : InputStream.transferTo, utilisé ci-dessus pour copier les flux.
  • Java 11 : javax.xml.bind.DatatypeConverter.printBase64Binary disparaît avec le retrait de JAXB du JDK.
  • Java 18 : UTF-8 devient le jeu de caractères par défaut.

Kotlin peut utiliser tout ce qui précède ; il a aussi sa propre API multiplateforme, présentée dans Base64 en Kotlin.

FAQ

Que signifie « Illegal base64 character 5f » ?

Le nombre est le caractère fautif en hexadécimal. 5f correspond à _ et 2d à - : vous décodez du Base64 URL-safe avec getDecoder(). Utilisez plutôt getUrlDecoder(). a est un saut de ligne et 20 une espace ; utilisez getMimeDecoder() ou supprimez les espaces.

Faut-il encore utiliser sun.misc.BASE64Encoder ou javax.xml.bind.DatatypeConverter ?

Non. sun.misc.BASE64Encoder est une API interne qui a disparu des JDK récents, et javax.xml.bind a été retiré du JDK dans Java 11. java.util.Base64 remplace les deux.

Le décodeur Java accepte-t-il du Base64 sans remplissage ?

Oui. Base64.getDecoder().decode("aGk") renvoie les octets de hi. Les décodeurs acceptent un remplissage manquant, mais rejettent un remplissage incorrect.

Comment encoder en Base64 sous Android ?

À partir du niveau d’API 26, java.util.Base64 est disponible. Le code plus ancien utilise android.util.Base64.encodeToString(bytes, Base64.NO_WRAP) ; sans NO_WRAP, des sauts de ligne sont ajoutés.

Continuer la lecture