Codificación como Base64 en Java

317

Necesito codificar algunos datos en la codificación Base64 en Java. ¿Cómo puedo hacer eso? ¿Cuál es el nombre de la clase que proporciona un codificador Base64?


Traté de usar la sun.misc.BASE64Encoderclase, sin éxito. Tengo la siguiente línea de código Java 7:

wr.write(new sun.misc.BASE64Encoder().encode(buf));

Estoy usando Eclipse. Eclipse marca esta línea como un error. Importé las bibliotecas requeridas:

import sun.misc.BASE64Encoder;
import sun.misc.BASE64Decoder;

Pero, de nuevo, ambos se muestran como errores. Encontré una publicación similar aquí .

Usé Apache Commons como la solución sugerida al incluir:

import org.apache.commons.*;

e importar los archivos JAR descargados de: http://commons.apache.org/codec/

Pero el problema aún existe. Eclipse todavía muestra los errores mencionados anteriormente. ¿Qué tengo que hacer?

Jurado A
fuente
77
Mi consejo: lea el mensaje de error e intente comprender lo que dice.
JB Nizet
27
Se supone que no debes usar clases bajosun.**
onon15
16
No son parte de la API pública; se pueden cambiar, eliminar o lo que sea sin previo aviso. Algunos de ellos pueden ser experimentales o simplemente no de grado de producción. oracle.com/technetwork/java/faq-sun-packages-142232.html
onon15
55
O utilice JAXB DatatypeConverter, que se incluye como estándar en Java 6 y versiones posteriores.
Ian Roberts
99
java.util.Base64 está disponible en Java 8
earcam

Respuestas:

621

Necesita cambiar la importación de su clase:

import org.apache.commons.codec.binary.Base64;

Y luego cambie su clase para usar la clase Base64.

Aquí hay un código de ejemplo:

byte[] encodedBytes = Base64.encodeBase64("Test".getBytes());
System.out.println("encodedBytes " + new String(encodedBytes));
byte[] decodedBytes = Base64.decodeBase64(encodedBytes);
System.out.println("decodedBytes " + new String(decodedBytes));

Luego lea por qué no debe usar los paquetes sun. * .


Actualización (2016-12-16)

Ahora puede usar java.util.Base64con Java 8. Primero, impórtelo como lo hace normalmente:

import java.util.Base64;

Luego use los métodos estáticos Base64 de la siguiente manera:

byte[] encodedBytes = Base64.getEncoder().encode("Test".getBytes());
System.out.println("encodedBytes " + new String(encodedBytes));
byte[] decodedBytes = Base64.getDecoder().decode(encodedBytes);
System.out.println("decodedBytes " + new String(decodedBytes));

Si desea codificar directamente una cadena y obtener el resultado como una cadena codificada, puede usar esto:

String encodeBytes = Base64.getEncoder().encodeToString((userName + ":" + password).getBytes());

Ver la documentación de Java para Base64 para obtener más información.

Franco
fuente
¿Necesito descargar algún paquete externo para que esto funcione? En caso afirmativo, ¿cuál?
abortado el
2
No, no necesitas descargar nada afaik
pratnala
16
org.apache.commons.codec.binary.Base64 no parece una biblioteca predeterminada. Supongo que debes incluir apache commons para eso. ¿Correcto?
Robert Reiz
@Frank La decodificación de los bytes a la vez genera un error OutOfMemory. Cualquier idea lo procesa en el búfer
xyz
225

Utilice la clase de Java 8 nunca es demasiado tarde para unirse a la diversión: java.util.Base64

new String(Base64.getEncoder().encode(bytes));
bratan
fuente
11
Aunque es un comentario trivial, tenga en cuenta que si usa eso, no es compatible con versiones anteriores de Java, que son (al menos en este momento) probablemente mucho más frecuentes.
dcoder
También elegiría la clase de Java 8 es posible. Actualmente estoy trabajando en una clase para eliminar la biblioteca apache commons de nuestro proyecto de primavera. La mayoría de las cosas se pueden reemplazar fácilmente con el método de las bibliotecas Spring o jdk.
Adrian Cosma el
68

En Java 8 se puede hacer como: Base64.getEncoder (). EncodeToString (string.getBytes (StandardCharsets.UTF_8))

Aquí hay un breve ejemplo completo e independiente:

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

public class Temp {
    public static void main(String... args) throws Exception {
        final String s = "old crow medicine show";
        final byte[] authBytes = s.getBytes(StandardCharsets.UTF_8);
        final String encoded = Base64.getEncoder().encodeToString(authBytes);
        System.out.println(s + " => " + encoded);
    }
}

Salida:

old crow medicine show => b2xkIGNyb3cgbWVkaWNpbmUgc2hvdw==
Kirby
fuente
3
¿Por qué no hay constantes Charset en la biblioteca estándar de Java, oh por qué?
Lukasz Wiktor
44
Buena pregunta, Lukasz! En realidad, los hay. ¡Olvidé! java.nio.charset.StandardCharsets. Editaré mi respuesta. Ver stackoverflow.com/questions/1684040/…
Kirby
67

También puedes convertir usando la codificación Base64. Para hacer esto, puedes usar el javax.xml.bind.DatatypeConverter#printBase64Binarymétodo.

Por ejemplo:

byte[] salt = new byte[] { 50, 111, 8, 53, 86, 35, -19, -47 };
System.out.println(DatatypeConverter.printBase64Binary(salt));
stinepike
fuente
44
Si bien esto funciona, la documentación indica específicamente: DatatypeConverterInterface es para uso exclusivo del proveedor JAXB.
gebirgsbärbel
11
Creo que @gebirgsbaerbel está mal, cualquiera puede usar el método printX () y parseX (), lo único que es solo para JAXB es el setDatatypeConverter()método (que luego debe llamarse para los proveedores JAXB).
PhoneixS
99
Finalmente, la clase Base64 de Java 8 será el camino a seguir. Pero si tiene que apuntar a Java 7 mientras tanto, esta solución es buena ya que no depende de bibliotecas externas.
dana
44
Esto no funciona en Java 9. Peor aún, el código compilado para Java 7 usando javax.xml.bind. * Fallará en Runtime bajo Java 9.
Stephen M -on strike-
21

Google Guava es otra opción para codificar y decodificar datos Base64:

Configuración de POM:

<dependency>
   <artifactId>guava</artifactId>
   <groupId>com.google.guava</groupId>
   <type>jar</type>
   <version>14.0.1</version>
</dependency>

Código de muestra:

String inputContent = "Hello Việt Nam";
String base64String = BaseEncoding.base64().encode(inputContent.getBytes("UTF-8"));

// Decode
System.out.println("Base64:" + base64String); // SGVsbG8gVmnhu4d0IE5hbQ==
byte[] contentInBytes = BaseEncoding.base64().decode(base64String);
System.out.println("Source content: " + new String(contentInBytes, "UTF-8")); // Hello Việt Nam
aunque
fuente
10

Eclipse le da un error / advertencia porque está tratando de usar clases internas que son específicas de un proveedor de JDK y no forman parte de la API pública. Jakarta Commons proporciona su propia implementación de códecs base64, que por supuesto residen en un paquete diferente. Elimine esas importaciones y deje que Eclipse importe las clases de Commons adecuadas para usted.

Marko Topolnik
fuente
El proyecto de Yakarta ya no existe . Se ha mezclado y emparejado (y el nombre se ha reutilizado para Java EE ). ¿Puedes actualizar tu respuesta y proporcionar algunas referencias? Por ejemplo, es ahora la clase Base64deorg.apache.commons.codec.binary ? ¿Es ahora Apache Commons para este contexto?
Peter Mortensen el
9

Para convertir esto, necesita un codificador y decodificador que obtendrá de Base64Coder, un codificador / decodificador Base64 de código abierto en Java . Es el archivo Base64Coder.java que necesitará.

Ahora para acceder a esta clase según sus requisitos, necesitará la siguiente clase:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Base64 {

    public static void main(String args[]) throws IOException {
        /*
         * if (args.length != 2) {
         *     System.out.println(
         *         "Command line parameters: inputFileName outputFileName");
         *     System.exit(9);
         * } encodeFile(args[0], args[1]);
         */
        File sourceImage = new File("back3.png");
        File sourceImage64 = new File("back3.txt");
        File destImage = new File("back4.png");
        encodeFile(sourceImage, sourceImage64);
        decodeFile(sourceImage64, destImage);
    }

    private static void encodeFile(File inputFile, File outputFile) throws IOException {
        BufferedInputStream in = null;
        BufferedWriter out = null;
        try {
            in = new BufferedInputStream(new FileInputStream(inputFile));
            out = new BufferedWriter(new FileWriter(outputFile));
            encodeStream(in, out);
            out.flush();
        }
        finally {
            if (in != null)
                in.close();
            if (out != null)
                out.close();
        }
    }

    private static void encodeStream(InputStream in, BufferedWriter out) throws IOException {
        int lineLength = 72;
        byte[] buf = new byte[lineLength / 4 * 3];
        while (true) {
            int len = in.read(buf);
            if (len <= 0)
                break;
            out.write(Base64Coder.encode(buf, 0, len));
            out.newLine();
        }
    }

    static String encodeArray(byte[] in) throws IOException {
        StringBuffer out = new StringBuffer();
        out.append(Base64Coder.encode(in, 0, in.length));
        return out.toString();
    }

    static byte[] decodeArray(String in) throws IOException {
        byte[] buf = Base64Coder.decodeLines(in);
        return buf;
    }

    private static void decodeFile(File inputFile, File outputFile) throws IOException {
        BufferedReader in = null;
        BufferedOutputStream out = null;
        try {
            in = new BufferedReader(new FileReader(inputFile));
            out = new BufferedOutputStream(new FileOutputStream(outputFile));
            decodeStream(in, out);
            out.flush();
        }
        finally {
            if (in != null)
                in.close();
            if (out != null)
                out.close();
        }
    }

    private static void decodeStream(BufferedReader in, OutputStream out) throws IOException {
        while (true) {
            String s = in.readLine();
            if (s == null)
                break;
            byte[] buf = Base64Coder.decodeLines(s);
            out.write(buf);
        }
    }
}

En Android, puede convertir su mapa de bits a Base64 para cargarlo en un servidor o servicio web.

Bitmap bmImage = //Data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmImage.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] imageData = baos.toByteArray();
String encodedImage = Base64.encodeArray(imageData);

Esta "imagen codificada" es una representación de texto de su imagen. Puede usar esto para cargar o para reproducir directamente en una página HTML como se muestra a continuación ( referencia ):

<img alt="" src="data:image/png;base64,<?php echo $encodedImage; ?>" width="100px" />
<img alt="" src="data:image/png;base64,/9j/4AAQ...........1f/9k=" width="100px" />

Documentación: http://dwij.co.in/java-base64-image-encoder

Desarrollador web en Pune
fuente
El último enlace (dwij.co.in) está roto (404).
Peter Mortensen el
9

Aquí están mis dos centavos ... Java 8 contiene su propia implementación de Base64 . Sin embargo, encontré una diferencia ligeramente inquietante. Para ilustrar, proporcionaré un ejemplo de código:

Mi envoltorio de códec:

public interface MyCodec
{
  static String apacheDecode(String encodedStr)
  {
    return new String(Base64.decodeBase64(encodedStr), Charset.forName("UTF-8"));
  }

  static String apacheEncode(String decodedStr)
  {
    byte[] decodedByteArr = decodedStr.getBytes(Charset.forName("UTF-8"));
    return Base64.encodeBase64String(decodedByteArr);
  }

  static String javaDecode(String encodedStr)
  {
    return new String(java.util.Base64.getDecoder().decode(encodedStr), Charset.forName("UTF-8"));
  }

  static String javaEncode(String decodedStr)
  {
    byte[] decodedByteArr = decodedStr.getBytes(Charset.forName("UTF-8"));
    return java.util.Base64.getEncoder().encodeToString(decodedByteArr);
  }
}

Clase de prueba:

public class CodecDemo
{
  public static void main(String[] args)
  {
    String decodedText = "Hello World!";

    String encodedApacheText = MyCodec.apacheEncode(decodedText);
    String encodedJavaText = MyCodec.javaEncode(decodedText);

    System.out.println("Apache encoded text: " + MyCodec.apacheEncode(encodedApacheText));
    System.out.println("Java encoded text: " + MyCodec.javaEncode(encodedJavaText));

    System.out.println("Encoded results equal: " + encodedApacheText.equals(encodedJavaText));

    System.out.println("Apache decode Java: " + MyCodec.apacheDecode(encodedJavaText));
    System.out.println("Java decode Java: " + MyCodec.javaDecode(encodedJavaText));

    System.out.println("Apache decode Apache: " + MyCodec.apacheDecode(encodedApacheText));
    System.out.println("Java decode Apache: " + MyCodec.javaDecode(encodedApacheText));
  }
}

SALIDA:

Apache encoded text: U0dWc2JHOGdWMjl5YkdRaA0K

Java encoded text: U0dWc2JHOGdWMjl5YkdRaA==
Encoded results equal: false
Apache decode Java: Hello World!
Java decode Java: Hello World!
Apache decode Apache: Hello World!
Exception in thread "main" java.lang.IllegalArgumentException: Illegal base64 character d
    at java.util.Base64$Decoder.decode0(Base64.java:714)
    at java.util.Base64$Decoder.decode(Base64.java:526)
    at java.util.Base64$Decoder.decode(Base64.java:549)

Observe que el texto codificado de Apache contiene saltos de línea adicionales (espacios en blanco) al final. Por lo tanto, para que mi códec produzca el mismo resultado independientemente de la implementación de Base64, tuve que recurrir trim()al texto codificado de Apache. En mi caso, simplemente agregué la llamada al método mencionado anteriormente en mi códec de la apacheDecode()siguiente manera:

return Base64.encodeBase64String(decodedByteArr).trim();

Una vez que se realizó este cambio, los resultados son los que esperaba comenzar:

Apache encoded text: U0dWc2JHOGdWMjl5YkdRaA==
Java encoded text: U0dWc2JHOGdWMjl5YkdRaA==
Encoded results equal: true
Apache decode Java: Hello World!
Java decode Java: Hello World!
Apache decode Apache: Hello World!
Java decode Apache: Hello World!

CONCLUSIÓN : Si desea cambiar de Apache Base64 a Java, debe:

  1. Decodifique texto codificado con su decodificador Apache.
  2. Codifique el texto resultante (sin formato) con Java.

Si cambia sin seguir estos pasos, lo más probable es que tenga problemas. Así es como hice este descubrimiento.

hfontanez
fuente
8

En Android, use los métodos estáticos de la clase de utilidad android.util.Base64 . La documentación referenciada dice que la clase Base64 se agregó en el nivel de API 8 ( Android 2.2 (Froyo)).

import android.util.Base64;

byte[] encodedBytes = Base64.encode("Test".getBytes());
Log.d("tag", "encodedBytes " + new String(encodedBytes));

byte[] decodedBytes = Base64.decode(encodedBytes);
Log.d("tag", "decodedBytes " + new String(decodedBytes));
Yojimbo
fuente
Esta es la mejor respuesta si está desarrollando para Android y no puede usar Java 8.
Craig Brown
6

Apache Commons tiene una buena implementación de Base64. Puedes hacer esto tan simple como:

// Encrypt data on your side using BASE64
byte[] bytesEncoded = Base64.encodeBase64(str .getBytes());
System.out.println("ecncoded value is " + new String(bytesEncoded));

// Decrypt data on other side, by processing encoded data
byte[] valueDecoded= Base64.decodeBase64(bytesEncoded );
System.out.println("Decoded value is " + new String(valueDecoded));

Puede encontrar más detalles sobre la codificación base64 en la codificación Base64 utilizando Java y JavaScript .

faisalbhagat
fuente
Tenga en cuenta que esto supone que la cadena está codificada en el juego de caracteres predeterminado
Kirby
6

Si está utilizando Spring Framework al menos la versión 4.1, puede usar la clase org.springframework.util.Base64Utils :

byte[] raw = { 1, 2, 3 };
String encoded = Base64Utils.encodeToString(raw);
byte[] decoded = Base64Utils.decodeFromString(encoded);

Delegará a Java Base64, Apache Commons Codec o JAXB DatatypeConverter, dependiendo de lo que esté disponible.

holmis83
fuente
4

Ejemplo simple con Java 8:

import java.util.Base64;

String str = "your string";
String encodedStr = Base64.getEncoder().encodeToString(str.getBytes("utf-8"));
z3d0
fuente
3

En Java 7 codifiqué este método

import javax.xml.bind.DatatypeConverter;

public static String toBase64(String data) {
    return DatatypeConverter.printBase64Binary(data.getBytes());
}
Daniel De León
fuente
Funciona en Java 7 y 8, pero no en Java 9. Peor aún, si compila esto en Java 7 u 8, se compilará y obtendrá una ClassDefNotFoundException en tiempo de ejecución en Java 9.
Stephen M -on strike-
1

Intenté con el siguiente fragmento de código. Funcionó bien :-)

com.sun.org.apache.xml.internal.security.utils.Base64.encode("The string to encode goes here");
tmh
fuente
0
public String convertImageToBase64(String filePath) {
    byte[] fileContent = new byte[0];
    String base64encoded = null;
    try {
        fileContent = FileUtils.readFileToByteArray(new File(filePath));
    } catch (IOException e) {
        log.error("Error reading file: {}", filePath);
    }
    try {
        base64encoded = Base64.getEncoder().encodeToString(fileContent);
    } catch (Exception e) {
        log.error("Error encoding the image to base64", e);
    }
    return base64encoded;
}
ghandour abdelkrim
fuente