Base64 convierte bytes en texto imprimible para poder meterlos donde solo caben caracteres: una URL, una cabecera HTTP, un correo, un JSON. Desde Java 8 está en el JDK y no hace falta ninguna biblioteca.
También te puede interesar
Ida y vuelta
import java.nio.charset.StandardCharsets;
import java.util.Base64;
void main() {
String original = "decodigo.com: año 2026 ñ";
String cod = Base64.getEncoder().encodeToString(original.getBytes(StandardCharsets.UTF_8));
IO.println("codificado : " + cod);
byte[] bytes = Base64.getDecoder().decode(cod);
IO.println("decodificado: " + new String(bytes, StandardCharsets.UTF_8));
}salidacodificado : ZGVjb2RpZ28uY29tOiBhw7FvIDIwMjYgw7E= decodificado: decodigo.com: año 2026 ñ
StandardCharsets.UTF_8 en los dos lados y olvídate.La variante para URL
String texto = "subcarpeta/archivo?x=1";
IO.println("estándar: " + Base64.getEncoder().encodeToString(texto.getBytes(UTF_8)));
IO.println("para URL: " + Base64.getUrlEncoder().withoutPadding()
.encodeToString(texto.getBytes(UTF_8)));salidaestándar: c3ViY2FycGV0YS9hcmNoaXZvP3g9MQ== para URL: c3ViY2FycGV0YS9hcmNoaXZvP3g9MQ
El alfabeto normal usa + y /, que en una URL significan otra cosa y hay que volver a escapar. getUrlEncoder los cambia por - y _. El = del final es relleno; withoutPadding() lo quita, y el decodificador lo acepta igual. Para decodificar hay que usar getUrlDecoder: los alfabetos no son intercambiables.
Hay un tercero, getMimeEncoder(), que parte la salida en líneas de 76 caracteres porque así lo pide el correo electrónico.
Un archivo
String cod = Base64.getEncoder().encodeToString(Files.readAllBytes(Path.of("foto.png")));
Files.write(Path.of("copia.png"), Base64.getDecoder().decode(cod));Es lo que hay detrás de las imágenes incrustadas en HTML con data:image/png;base64,… y de los adjuntos de un correo. Para archivos grandes conviene Base64.getEncoder().wrap(flujo), que trabaja por partes y no carga todo en memoria.
Dos cosas que hay que tener claras
IO.println("original : " + original.getBytes(UTF_8).length + " bytes");
IO.println("codificado: " + cod.length() + " caracteres");salidaoriginal : 26 bytes codificado: 36 caracteres
Base64 engorda. Cada 3 bytes se convierten en 4 caracteres, así que el resultado ocupa un tercio más. Mandar una imagen en Base64 dentro de un JSON cuesta un 33 % más de red que mandarla como archivo.
Cuando lo que llega no es Base64
Base64.getDecoder().decode("esto no es base64 válido!!");salidaIllegalArgumentException: Illegal base64 character 20
El 20 es hexadecimal: el espacio. El decodificador estricto rechaza cualquier carácter fuera del alfabeto, saltos de línea incluidos; si lo que recibes puede venir partido en líneas, usa getMimeDecoder(), que los ignora.
Más información en inglés: Base64 encoding and decoding in Java.
Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.