Codificación Base64 en Java — java.util.Base64
Usa el Codificador Base64 Online gratuito directamente en tu navegador — sin instalación.
Probar Codificador Base64 Online online →Cada vez que configuro un encabezado HTTP Basic Auth, inserto un certificado en un secreto de Kubernetes o envío datos binarios a través de una API JSON, el primer paso es siempre el mismo: codificar en Base64 los bytes en bruto para obtener una cadena segura en ASCII. Java facilita esto con java.util.Base64, la API estándar disponible desde Java 8 que reemplazó al deprecado sun.misc.BASE64Encoder. Para una codificación rápida sin escribir código, el Codificador Base64 de ToolDeck lo resuelve al instante en el navegador. Esta guía cubre Base64.getEncoder(), getUrlEncoder(), getMimeEncoder(), codificación de archivos, streaming con wrap(OutputStream), y los errores que afectan incluso a desarrolladores Java con experiencia. Todos los ejemplos compilan en Java 8 hasta Java 21+.
- ✓Base64.getEncoder().encodeToString(bytes) es el one-liner estándar — incluido en el JDK desde Java 8, sin cambios en Java 17 y 21.
- ✓Pasa siempre StandardCharsets.UTF_8 a String.getBytes() antes de codificar — omitirlo usa el predeterminado de la plataforma, que varía entre JVMs.
- ✓getUrlEncoder() produce salida URL-safe (- en lugar de +, _ en lugar de /) y withoutPadding() elimina los caracteres = del final.
- ✓getMimeEncoder() inserta saltos de línea cada 76 caracteres — requerido por los formatos de correo (MIME) y certificados PEM.
- ✓Para archivos grandes, usa Base64.getEncoder().wrap(OutputStream) para transmitir sin cargar el archivo completo en memoria.
¿Qué es la codificación Base64?
Base64 convierte datos binarios arbitrarios en una cadena compuesta por 64 caracteres ASCII imprimibles: A-Z, a-z, 0-9, +, y /. Cada 3 bytes de entrada producen exactamente 4 caracteres Base64. Si la longitud de la entrada no es múltiplo de 3, se añaden uno o dos caracteres de relleno =. La salida codificada es siempre aproximadamente un 33% más grande que los datos originales.
Base64 no es cifrado. Cualquier persona con la cadena codificada puede decodificarla. Su propósito es la seguridad en el transporte: los encabezados HTTP, los payloads JSON, los documentos XML y el cuerpo de los correos electrónicos son protocolos de texto que no pueden transportar bytes binarios en bruto sin corrupción. Los casos de uso comunes en Java incluyen HTTP Basic Authentication, incrustar certificados PEM, almacenar datos binarios en columnas de texto de bases de datos y construir segmentos de tokens JWT.
deploy-svc:sk_live_4eC39HqLyjWDarjtT1zdp7dc
ZGVwbG95LXN2Yzpza19saXZlXzRlQzM5SHFMeWpXRGFyanRUMXpkcDdkYw==
Base64.getEncoder().encodeToString() — La API estándar
java.util.Base64 se introdujo en Java 8 como el reemplazo oficial de sun.misc.BASE64Encoder. La clase proporciona tres métodos de fábrica estáticos — cada uno devuelve una instancia de la clase anidada Base64.Encoder — que cubren las tres variantes de Base64 definidas en el RFC 4648. No se necesita ninguna librería de terceros. Sin dependencia Maven. Solo importa y llama.
Ejemplo mínimo — Codificar un String
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
}
}El paso clave que la mayoría de desarrolladores Java pasan por alto la primera vez: un String debe convertirse a byte[] antes de codificar. Base64 opera sobre bytes, no sobre caracteres. encodeToString() acepta un byte[] y devuelve el String Base64 directamente. Si necesitas el resultado codificado como bytes en lugar de un String, usa encode(byte[]) — devuelve un byte[] de los caracteres Base64 codificados en ASCII, útil cuando escribes directamente en un OutputStream o construyes tramas de protocolo binario.
HTTP Basic Auth — El caso de uso más común
HTTP Basic Authentication es probablemente la razón más habitual por la que los desarrolladores Java recurren a la codificación Base64. La especificación (RFC 7617) requiere que la cadena de credenciales username:password esté codificada en Base64 y colocada en el encabezado Authorization. He visto esto hacerse mal más veces de las que puedo contar — normalmente por olvidar el separador de dos puntos o por codificar los componentes por separado.
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
}
}Ciclo completo — Codificar y decodificar
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";
// Codificar
String encoded = Base64.getEncoder()
.encodeToString(original.getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);
// WC1Db3JyZWxhdGlvbi1JRDogcmVxXzhhNGYyYzkxLWU3YjMtNGQ1Ni05MDEyLTNmN2E4YjljMGQxZQ==
// Decodificar
byte[] decodedBytes = Base64.getDecoder().decode(encoded);
String decoded = new String(decodedBytes, StandardCharsets.UTF_8);
System.out.println(original.equals(decoded)); // true
}
}java.util.Base64 es idéntica desde Java 8 hasta Java 17 y Java 21. No se necesita ninguna migración al actualizar el JDK. El mismo código compila y se ejecuta en cualquier versión desde Java 8.Codificación de datos que no son String — byte[], UUID y marcas de tiempo
La codificación Base64 en Java siempre comienza con un byte[]. Los Strings se convierten mediante getBytes(StandardCharsets.UTF_8), pero otros tipos necesitan un paso de conversión previo. Los UUIDs, marcas de tiempo e identificadores numéricos deben serializarse a una representación de string o bytes antes de poder codificarlos en Base64.
UUID — Codificar como representación en String
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);
// NmJhN2I4MTAtOWRhZC0xMWQxLTgwYjQtMDBjMDRmZDQzMGM4UUID compacto — Codificar los 16 bytes en bruto
Si quieres un resultado codificado más corto, extrae los 128 bits del UUID como 16 bytes en bruto en lugar de convertirlo a su forma de string de 36 caracteres. La salida Base64 pasa de 48 caracteres a 24.
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 caracteres frente a 48 del enfoque basado en stringMarca de tiempo y payload mixto
import java.time.Instant;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
// Simulando un payload estilo 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, sin relleno)toString() sobre un byte[] esperando obtener su contenido — eso te da el hash de identidad del arreglo, como [B@6d06d69c. Usa new String(bytes, StandardCharsets.UTF_8) o pasa el arreglo de bytes directamente a encodeToString().Referencia de métodos de Base64.Encoder
La clase java.util.Base64 expone tres métodos de fábrica, cada uno devuelve una instancia de Base64.Encoder configurada para una variante específica. Las instancias del codificador son thread-safe y sin estado — créalas una vez y reutilízalas.
Base64.getUrlEncoder() — Codificación URL-Safe
El codificador URL-safe usa un alfabeto alternativo donde + se convierte en - y / se convierte en _, tal como se define en la sección 5 del RFC 4648. Esto importa cuando el string Base64 aparece en un parámetro de consulta de URL, un nombre de archivo o un valor de cookie — los caracteres del Base64 estándar entran en conflicto con los delimitadores de URL y los caracteres reservados del sistema de archivos.
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); // Codificador estándar — contiene + y / que rompen las URLs String standard = Base64.getEncoder().encodeToString(data); System.out.println(standard); // aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s/c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw== // Codificador URL-safe — seguro para parámetros de consulta y nombres de archivo String urlSafe = Base64.getUrlEncoder().encodeToString(data); System.out.println(urlSafe); // aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw== // URL-safe sin relleno — para JWTs y tokens compactos String noPadding = Base64.getUrlEncoder().withoutPadding().encodeToString(data); System.out.println(noPadding); // aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw
La variante withoutPadding() elimina los caracteres de relleno = del final. Las especificaciones JWT requieren Base64 URL-safe sin relleno para los segmentos de encabezado y payload, así que getUrlEncoder().withoutPadding() es exactamente la llamada que necesitas cuando construyes o manipulas tokens JWT manualmente.
withoutPadding() devuelve una nueva instancia de codificador — no modifica el original. Ambos pueden asignarse a campos static final y reutilizarse de forma segura entre hilos.Codificar desde archivo y respuesta de API
Los dos escenarios más comunes en el mundo real para la codificación Base64 en Java: leer un archivo binario del disco (certificados, imágenes, paquetes de configuración) y codificar datos recibidos de una respuesta HTTP.
Codificar un archivo en Base64
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("Codificado: %d chars%n", encoded.length());
// Escribir el contenido codificado en un archivo de texto
Files.writeString(
Path.of("certs/server.pem.b64"),
encoded
);
} catch (java.io.IOException e) {
System.err.println("Error al leer el archivo: " + e.getMessage());
}
}
}Codificar el cuerpo de una respuesta de API
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("Codificados %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("La petición falló: " + e.getMessage());
}
}
}Una nota rápida antes de la sección de línea de comandos: si solo necesitas pegar un archivo o una respuesta de API y obtener la salida Base64 sin escribir código, el Codificador Base64 online maneja tanto entradas de texto como binarias.
Codificación Base64 desde la línea de comandos
A veces solo necesitas codificar un string o un archivo desde la terminal — sin proyecto Java, sin IDE, sin paso de compilación. La mayoría de sistemas Unix incluyen el comando base64, y si tienes el JDK instalado, puedes usar jshell para un enfoque nativo de Java.
# macOS / Linux — codificar un string
echo -n "deploy-bot:sk_prod_9f2a7c4e" | base64
# ZGVwbG95LWJvdDpza19wcm9kXzlmMmE3YzRl
# Codificar un archivo
base64 < certs/server.pem > certs/server.pem.b64
# Usando jshell (JDK 9+)
echo 'System.out.println(java.util.Base64.getEncoder().encodeToString("deploy-bot:sk_prod_9f2a7c4e".getBytes()))' | jshell -
# Usando java directamente con un one-liner
java -e 'System.out.println(java.util.Base64.getEncoder().encodeToString(args[0].getBytes()))' "my-secret"
# Nota: java -e requiere JDK 23+ (JEP 477)El enfoque con jshell es especialmente útil cuando necesitas verificar que tu código Java produce la misma salida que una herramienta Unix, o cuando depuras una discrepancia entre lo que envía tu servicio y lo que espera el receptor. Tengo un alias de shell para eso.
base64 usa -D para decodificar. En Linux (GNU coreutils) usa -d. El comportamiento de codificación es idéntico en ambos. El indicador -w 0 en Linux deshabilita el ajuste de línea en la salida, que es lo que normalmente quieres al redirigir a otros comandos.Apache Commons Codec — Alternativa de alto rendimiento
Para la mayoría de aplicaciones, java.util.Base64 es suficientemente rápido. Pero si procesas millones de operaciones de codificación en un bucle ajustado — como pipelines de ingesta de logs o brokers de mensajes de alto rendimiento — vale la pena comparar con Apache Commons Codec. Existe desde mucho antes de Java 8 y ofrece una alternativa sólida con una superficie de API algo diferente.
// 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);
// Codificación estándar
String encoded = Base64.encodeBase64String(telemetryPayload);
// Codificación URL-safe
String urlSafe = Base64.encodeBase64URLSafeString(telemetryPayload);
// Comprobar si un string es Base64 válido
boolean valid = Base64.isBase64(encoded);
System.out.println(valid); // trueApache Commons Codec también proporciona Base64OutputStream y Base64InputStream para escenarios de streaming, e incluye un método de validación que el codificador del JDK no tiene. Si Commons Codec ya está en tu árbol de dependencias (viene incluido en muchos proyectos Apache), no hay ninguna razón para no usarlo.
Guava BaseEncoding
La librería Guava de Google incluye BaseEncoding, que proporciona una API fluida para Base64 con separadores de línea configurables, control de relleno y soporte para los alfabetos estándar y URL-safe. La API es muy legible, pero añadir Guava (aproximadamente 3 MB) solo para la codificación Base64 es excesivo. Si Guava ya está en tu proyecto por sus utilidades de colecciones o caché, la API de codificación es un buen complemento.
// 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 estándar
String standard = BaseEncoding.base64().encode(webhookPayload);
// URL-safe
String urlSafe = BaseEncoding.base64Url().encode(webhookPayload);
// Sin relleno
String noPad = BaseEncoding.base64Url().omitPadding().encode(webhookPayload);
// Con separadores de línea (estilo PEM)
String wrapped = BaseEncoding.base64()
.withSeparator("\n", 64)
.encode(webhookPayload);Base64.getMimeEncoder() — Salida MIME y PEM con saltos de línea
El codificador MIME inserta saltos de línea \r\n cada 76 caracteres, siguiendo la especificación MIME (RFC 2045). Los certificados PEM, los adjuntos de correo S/MIME y algunas APIs heredadas esperan este formato. Los codificadores estándar y URL-safe producen una sola línea sin interrupciones — si pasas su salida a un sistema que espera Base64 con saltos de línea, puede fallar silenciosamente o rechazar los datos.
import java.util.Base64;
import java.nio.charset.StandardCharsets;
// Simular el cuerpo de un certificado PEM
byte[] certData = new byte[256]; // En la práctica, leer desde un archivo .der
new java.security.SecureRandom().nextBytes(certData);
// Codificador MIME predeterminado — 76 chars por línea, separador \r\n
String mimeEncoded = Base64.getMimeEncoder().encodeToString(certData);
System.out.println(mimeEncoded);
// QYx2K3p8Xg7JmN1R+wFkLd... (76 chars)
// Ht5Bv9CzAq0PnSjYl8WxUe... (76 chars)
// ...
// Codificador MIME personalizado — 64 chars por línea (estándar PEM), separador \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() para tokens JWT, encabezados HTTP ni parámetros de URL. Los saltos de línea corromperán los datos en esos contextos. Usa getEncoder() o getUrlEncoder() en su lugar.Archivos grandes con streaming usando Base64.getEncoder().wrap()
Cargar un archivo completo en un byte[] con Files.readAllBytes() funciona para archivos pequeños, pero para archivos de más de 50-100 MB arriesgas un OutOfMemoryError. El JDK ofrece Base64.getEncoder().wrap(OutputStream), que devuelve un OutputStream que codifica los datos al vuelo mientras escribes en él. Los bytes codificados fluyen hacia el stream subyacente sin almacenar toda la entrada en memoria.
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("Transmitidos %d bytes a través del codificador Base64%n", totalBytes);
}
// Cerrar base64Out vacía automáticamente los bytes de relleno finales
}
}El bloque try-with-resources gestiona el vaciado y cierre. Un detalle que sorprende a muchos: el relleno Base64 final solo se escribe cuando se cierra el OutputStream envolvente. Si olvidas cerrarlo (o solo cierras el stream externo), los últimos caracteres de tu salida codificada pueden estar incompletos.
Streaming a un socket de red
El método wrap() funciona con cualquier OutputStream — salida de archivo, salida de socket, cuerpo de respuesta HTTP, incluso ByteArrayOutputStream. A continuación un ejemplo que escribe datos codificados en Base64 directamente en un buffer en memoria, útil para pruebas unitarias o para construir payloads que se enviarán por HTTP:
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)) {
// Escribir datos en trozos — simula la lectura desde un stream
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=
// Verificar el ciclo completo
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-segmentBufferedInputStream y es un buen equilibrio entre uso de memoria y sobrecarga de llamadas al sistema. Buffers más pequeños aumentan el número de llamadas de lectura/escritura; buffers más grandes desperdician memoria sin mejora significativa en el rendimiento.Instancias de codificador thread-safe — Almacena y reutiliza
El Base64.Encoder devuelto por los métodos de fábrica es inmutable y thread-safe. Llamar a Base64.getEncoder() en cada operación de codificación crea un nuevo objeto cada vez. La JVM probablemente lo optimice, pero almacenar el codificador en un campo static final deja clara la intención y evita asignaciones innecesarias en rutas críticas.
import java.util.Base64;
import java.nio.charset.StandardCharsets;
public class TokenService {
// Crear una vez, reutilizar en todas partes — thread-safe
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);
}
}Este patrón es especialmente útil en servicios Spring Boot donde una clase de utilidades gestiona la codificación en múltiples controladores o métodos de servicio. La llamada a withoutPadding() devuelve una nueva instancia de codificador, por lo que puedes almacenar las variantes con y sin relleno como campos separados. Cada llamada a encodeToString() o encode() es sin estado — no se necesita sincronización, no hay estado mutable compartido.
Errores comunes
Problema: String.getBytes() sin argumento de charset usa la codificación predeterminada de la plataforma, que es windows-1252 en Windows, UTF-8 en la mayoría de sistemas Linux, y varía en macOS. El mismo código produce salidas Base64 distintas en máquinas diferentes.
Solución: Pasa siempre StandardCharsets.UTF_8 de forma explícita.
String text = "Ключ доступа: prod-east"; byte[] bytes = text.getBytes(); // predeterminado de la plataforma — impredecible String encoded = Base64.getEncoder().encodeToString(bytes);
String text = "Ключ доступа: prod-east"; byte[] bytes = text.getBytes(StandardCharsets.UTF_8); String encoded = Base64.getEncoder().encodeToString(bytes);
Problema: Base64.getEncoder() produce los caracteres + y /. Cuando se colocan en una cadena de consulta de URL, + se interpreta como un espacio y / como un separador de ruta, corrompiendo silenciosamente el valor en el receptor.
Solución: Usa Base64.getUrlEncoder() para cualquier valor que vaya a aparecer en una URL.
// Token en parámetro de consulta URL — fallará
String token = Base64.getEncoder()
.encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;// Codificación URL-safe — sin caracteres + ni /
String token = Base64.getUrlEncoder()
.withoutPadding()
.encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;Problema: Codificar con getUrlEncoder() y decodificar con getDecoder() (o viceversa) lanza IllegalArgumentException porque - y _ no son válidos en el alfabeto Base64 estándar, y + y / no son válidos en el alfabeto URL-safe.
Solución: Decodifica siempre con el decodificador correspondiente: getUrlDecoder() para URL-safe, getDecoder() para estándar.
String encoded = Base64.getUrlEncoder()
.encodeToString(data);
// Más tarde...
byte[] decoded = Base64.getDecoder() // decodificador INCORRECTO
.decode(encoded);
// IllegalArgumentException si encoded contiene - o _String encoded = Base64.getUrlEncoder()
.encodeToString(data);
// Más tarde...
byte[] decoded = Base64.getUrlDecoder() // decodificador correcto
.decode(encoded);Problema: El codificador en streaming almacena en buffer hasta 2 bytes de entrada esperando un grupo completo de 3 bytes. Si no cierras el OutputStream envolvente, los últimos 1-4 caracteres Base64 (incluido el relleno) nunca se escriben.
Solución: Usa try-with-resources o llama a close() explícitamente en el stream envolvente antes de leer la salida.
ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStream b64os = Base64.getEncoder().wrap(baos); b64os.write(data); // baos.toString() está INCOMPLETO — faltan los bytes finales
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (OutputStream b64os = Base64.getEncoder().wrap(baos)) {
b64os.write(data);
} // close() vacía el relleno final
String encoded = baos.toString(); // completoMétodos de codificación Base64 — Comparativa
Para la mayoría de proyectos: java.util.Base64 es la elección correcta. Sin dependencias, incluido en el JDK, thread-safe y cubre las tres variantes del RFC 4648. Recurre a Apache Commons Codec solo si ya está en tu classpath y necesitas el método de validación isBase64() o el Base64OutputStream para streaming. El BaseEncoding de Guava es una opción razonable si tu proyecto ya depende de Guava, pero añadir una dependencia de 3 MB solo para Base64 es difícil de justificar.
Tres escenarios, tres opciones: ¿un servicio web estándar que necesita codificación para Basic Auth o JWT? Usa el JDK. ¿Un proyecto heredado que ya incluye Commons Codec a través de Spring o Apache HTTP Client? Úsalo — no tiene sentido tener dos librerías Base64 en el classpath. ¿Un proyecto que usa Guava para caché y colecciones? Usa BaseEncoding por su limpia API fluida. Nunca añadas una librería solo para codificación Base64 — la versión del JDK es suficientemente buena desde 2014.
Si necesitas verificar rápidamente un resultado codificado sin ejecutar tu código Java, pégalo en el Codificador Base64 para confirmar que la salida coincide con lo que produce tu código.
Preguntas frecuentes
¿Cómo se codifica un String en Base64 en Java?
Primero convierte el string a bytes con getBytes(StandardCharsets.UTF_8) y luego pasa el arreglo de bytes a Base64.getEncoder().encodeToString(). Especifica siempre UTF-8 de forma explícita: llamar a getBytes() sin un argumento de charset usa el predeterminado de la plataforma, que varía entre sistemas operativos y configuraciones de JVM.
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¿Cuál es la diferencia entre Base64.getEncoder() y Base64.getUrlEncoder()?
Ambos codifican en Base64, pero getUrlEncoder() usa el alfabeto URL-safe definido en la sección 5 del RFC 4648. Reemplaza + por - y / por _ para que la salida pueda aparecer en URLs y nombres de archivo sin necesidad de percent-encoding. El codificador estándar usa + y / que entran en conflicto con los parámetros de consulta y los segmentos de ruta de las URLs.
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 // (igual aquí, pero con + → - y / → _ cuando aparecen esos caracteres)
¿Es java.util.Base64 igual en Java 8 y Java 17?
Sí. La API de java.util.Base64 no ha cambiado desde que se introdujo en Java 8. La clase, sus clases anidadas Encoder y Decoder, y todos los métodos de fábrica (getEncoder, getUrlEncoder, getMimeEncoder) son idénticos en Java 8, 11, 17 y 21. No se necesitan migraciones ni cambios de código al actualizar la versión del JDK.
// Este código compila y se ejecuta de forma idéntica en Java 8 hasta 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==¿Cómo se codifica un archivo en Base64 en Java?
Lee el archivo en un arreglo de bytes con Files.readAllBytes(Path) y pásalo a Base64.getEncoder().encodeToString(). Para archivos grandes que no deben cargarse completamente en memoria, usa Base64.getEncoder().wrap(OutputStream) para transmitir la salida codificada.
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);¿Por qué se deprecó sun.misc.BASE64Encoder?
sun.misc.BASE64Encoder era una clase interna del JDK que nunca formó parte de la API pública. Vivía en el paquete sun.misc, que Oracle desaconsejó explícitamente usar. Java 8 introdujo java.util.Base64 como el reemplazo oficial, público y soportado. Desde Java 9 y el sistema de módulos, acceder a las clases de sun.misc genera advertencias o errores según la configuración del JDK.
// Forma antigua — NO usar, eliminada en JDKs modernos // import sun.misc.BASE64Encoder; // String encoded = new BASE64Encoder().encode(data); // Forma correcta desde Java 8 import java.util.Base64; String encoded = Base64.getEncoder().encodeToString(data);
¿Cómo se hace un ciclo completo de codificación y decodificación Base64 en Java?
Codifica con Base64.getEncoder().encodeToString(bytes) y decodifica con Base64.getDecoder().decode(encodedString). Convierte el arreglo de bytes decodificado de vuelta a un String usando new String(bytes, StandardCharsets.UTF_8). El ciclo completo preserva los datos originales exactamente, siempre que uses el mismo charset tanto en getBytes() como en new String().
import java.util.Base64; import java.nio.charset.StandardCharsets; // Codificar String original = "session_token=eyJhbGciOiJSUzI1NiJ9"; byte[] originalBytes = original.getBytes(StandardCharsets.UTF_8); String encoded = Base64.getEncoder().encodeToString(originalBytes); // Decodificar byte[] decodedBytes = Base64.getDecoder().decode(encoded); String decoded = new String(decodedBytes, StandardCharsets.UTF_8); System.out.println(original.equals(decoded)); // true
Herramientas relacionadas
- Decodificador Base64 — Decodifica strings Base64 de vuelta a su texto u forma binaria original — la operación inversa a la codificación.
- Codificador de URL — Aplica percent-encoding a strings para usarlos de forma segura en URLs — distinto del encoding URL-safe de Base64, pero frecuentemente usado junto a él.
- Decodificador JWT — Inspecciona tokens JWT cuyos segmentos de encabezado y payload están codificados en Base64url como JSON — decodifícalos sin necesidad de una librería.
- Formateador JSON — Formatea payloads JSON antes o después de la codificación Base64 — útil para depurar integraciones con APIs.
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.
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.