Encoding as Base64 in Java
Asked Answered
S

19

380

I need to encode some data in the Base64 encoding in Java. How do I do that? What is the name of the class that provides a Base64 encoder?


I tried to use the sun.misc.BASE64Encoder class, without success. I have the following line of Java 7 code:

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

I'm using Eclipse. Eclipse marks this line as an error. I imported the required libraries:

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

But again, both of them are shown as errors. I found a similar post here.

I used Apache Commons as the solution suggested by including:

import org.apache.commons.*;

and importing the JAR files downloaded from: http://commons.apache.org/codec/

But the problem still exists. Eclipse still shows the errors previously mentioned. What should I do?

Scrag answered 28/10, 2012 at 14:21 Comment(6)
My advice: read the error message, and try to understand what it says.Genip
You're not supposed to use classes under sun.**Adenovirus
@Adenovirus Why? Never heard of that. Please expatiate.Kakaaba
They are not part of the public API; they may be changed, removed or whatever without notice. Some of them may be experimental or just not production-grade. oracle.com/technetwork/java/faq-sun-packages-142232.htmlAdenovirus
Or use the JAXB DatatypeConverter which is included as standard in Java 6 and later.Quintinquintina
java.util.Base64 is available in Java 8Diandiana
L
721

You need to change the import of your class:

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

And then change your class to use the Base64 class.

Here's some example code:

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

Then read why you shouldn't use sun.* packages.


Update (2016-12-16)

You can now use java.util.Base64 with Java 8. First, import it as you normally do:

import java.util.Base64;

Then use the Base64 static methods as follows:

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

If you directly want to encode string and get the result as encoded string, you can use this:

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

See Java documentation for Base64 for more.

Leeleeann answered 28/10, 2012 at 14:25 Comment(5)
Do I need to download any external package for this to work? If yes, which?Unciform
No you don't need to download anything afaikBarrator
org.apache.commons.codec.binary.Base64 doesn't look like a default library. I guess you have to include apache commons for that. Right?Liability
@Leeleeann Decoding the bytes at once raise OutOfMemory error.Any idea process it in bufferSynthesis
commons.apache.org/proper/commons-codec/dependency-info.html e.g. gradle compile 'commons-codec:commons-codec:1.15'Feigin
R
260

Use Java 8's never-too-late-to-join-in-the-fun class: java.util.Base64

new String(Base64.getEncoder().encode(bytes));
Rupee answered 28/3, 2014 at 5:23 Comment(3)
Although a trivial comment, notice that if you use that you're not compatible with older versions of Java, which are (at least at this point in time) probably far more prevalent.Dialyze
I would also choose Java 8's class is possible. I am currently working on a class to remove the apache commons library from our spring project. Most of the stuff can be replaced easily with method from Spring libraries or jdk.Parliamentarian
Prefer the function that returns String type: Base64.getEncoder().encodeToString("blah".getBytes())Tripalmitin
I
89

In Java 8 it can be done as: Base64.getEncoder().encodeToString(string.getBytes(StandardCharsets.UTF_8))

Here is a short, self-contained complete example:

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

Output:

old crow medicine show => b2xkIGNyb3cgbWVkaWNpbmUgc2hvdw==
Insulin answered 12/11, 2014 at 22:16 Comment(2)
Why are there no Charset constants in Java standard library, oh why?!Neal
Good question, Lukasz! Actually, there are. I forgot! java.nio.charset.StandardCharsets. I'll edit my answer. See #1684540Insulin
T
68

You can also convert using Base64 encoding. To do this, you can use the javax.xml.bind.DatatypeConverter#printBase64Binary method.

For example:

byte[] salt = new byte[] { 50, 111, 8, 53, 86, 35, -19, -47 };
System.out.println(DatatypeConverter.printBase64Binary(salt));
Tartuffe answered 31/5, 2013 at 10:0 Comment(4)
While this works, the documentation specifically states: DatatypeConverterInterface is for JAXB provider use only.Herisau
I think that @gebirgsbaerbel is wrong, printX() and parseX() method can be used by any, the only thing that is for JAXB only is the setDatatypeConverter() method (which then must be called for JAXB providers).Cortezcortical
Eventually the Base64 class from Java 8 will be the way to go. But if you have to target Java 7 in the meantime, this solution is nice since it does not rely on external libraries.Gnash
This does not work under Java 9. Worse, code compiled for Java 7 using javax.xml.bind.* will fail at Runtime under Java 9.Containment
E
22

With Guava

pom.xml:

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

Sample code:

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

// decode
System.out.println("Base64:" + base64); // SGVsbG8gVmnhu4d0IE5hbQ==
byte[] bytes = BaseEncoding.base64().decode(base64);
System.out.println("Decoded: " + new String(bytes, "UTF-8")); // Hello Việt Nam
Exasperation answered 10/2, 2015 at 10:35 Comment(0)
B
12

Eclipse gives you an error/warning because you are trying to use internal classes that are specific to a JDK vendor and not part of the public API. Jakarta Commons provides its own implementation of base64 codecs, which of course reside in a different package. Delete those imports and let Eclipse import the proper Commons classs for you.

Blinker answered 28/10, 2012 at 14:26 Comment(1)
The Jakarta project is no longer. It has been mixed and matched (and the name reused for Java EE). Can you update your answer and provide some references? For instance, is it now class Base64 in org.apache.commons.codec.binary? Is it now Apache Commons for this context?Manard
C
11

For Java 6-7, the best option is to borrow code from the Android repository. It has no dependencies.

https://github.com/android/platform_frameworks_base/blob/master/core/java/android/util/Base64.java

Calandra answered 13/6, 2015 at 0:24 Comment(0)
P
11

Java 8 does contain its own implementation of Base64. However, I found one slightly disturbing difference. To illustrate, I will provide a code example:

My codec wrapper:

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

Test Class:

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

OUTPUT:

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)

Notice that the Apache encoded text contain additional line breaks (white spaces) at the end. Therefore, in order for my codec to yield the same result regardless of Base64 implementation, I had to call trim() on the Apache encoded text. In my case, I simply added the aforementioned method call to the my codec's apacheDecode() as follows:

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

Once this change was made, the results are what I expected to begin with:

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!

CONCLUSION: If you want to switch from Apache Base64 to Java, you must:

  1. Decode encoded text with your Apache decoder.
  2. Encode resulting (plain) text with Java.

If you switch without following these steps, most likely you will run into problems. That is how I made this discovery.

Polyadelphous answered 1/11, 2017 at 15:47 Comment(2)
truly interesting, indeed. These are the little things that can hit you hard in the face, when not expected code starts to failRazzia
@Razzia I found this out the wrong way. I had to implement in a business application and because of this issue, it exploded in my face. Fortunately, 1) I was working on a separate branch, and 2) I have pretty good diagnostics skills (especially when my back is against the wall LOL). I came here to learn how to do it, and ended up leaning that I should never fall of an answer as completely accurate even it was selected as the answer and/or had hundreds of upvotes. The devil is on the details.Polyadelphous
H
10

To convert this, you need an encoder & decoder which you will get from Base64Coder - an open-source Base64 encoder/decoder in Java. It is file Base64Coder.java you will need.

Now to access this class as per your requirement you will need the class below:

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

In Android you can convert your bitmap to Base64 for Uploading to a server or web service.

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

This “encodedImage” is text representation of your image. You can use this for either uploading purpose or for diplaying directly into an HTML page as below (reference):

<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" />

Documentation: http://dwij.co.in/java-base64-image-encoder

Hylomorphism answered 3/6, 2013 at 15:0 Comment(1)
The last link (dwij.co.in) is broken (404).Manard
Q
9

On Android, use the static methods of the android.util.Base64 utility class. The referenced documentation says that the Base64 class was added in API level 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));
Quit answered 23/8, 2016 at 17:2 Comment(1)
This is the best answer if you're developing for Android and you can't use Java 8.Vullo
A
8

If you are using Spring Framework at least version 4.1, you can use the org.springframework.util.Base64Utils class:

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

It will delegate to Java 8's Base64, Apache Commons Codec, or JAXB DatatypeConverter, depending on what is available.

Alvertaalves answered 19/8, 2016 at 12:23 Comment(0)
T
7

Apache Commons has a nice implementation of Base64. You can do this as simply as:

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

You can find more details about base64 encoding at Base64 encoding using Java and JavaScript.

Teaching answered 6/6, 2014 at 11:15 Comment(2)
Note that this assumes the string is encoded in the default charsetInsulin
Base64 is used for encoding, not encryption, so -1 for the "encrypt" and "decrypt".Boyt
P
6

Simple example with Java 8:

import java.util.Base64;

String str = "your string";
String encodedStr = Base64.getEncoder().encodeToString(str.getBytes("utf-8"));
Plutocracy answered 15/11, 2015 at 20:27 Comment(0)
G
6

In Java 7 I coded this method

import javax.xml.bind.DatatypeConverter;

public static String toBase64(String data) {
    return DatatypeConverter.printBase64Binary(data.getBytes());
}
Gerent answered 14/3, 2016 at 17:48 Comment(1)
Works under Java 7 and 8, but not Java 9. Worse, if you build this under Java 7 or 8 it will build and then you'll get a ClassDefNotFoundException at Runtime under Java 9.Containment
S
4

If you are stuck to an earlier version of Java than 8 but already using AWS SDK for Java, you can use com.amazonaws.util.Base64.

Summersummerhouse answered 12/8, 2016 at 11:59 Comment(0)
B
2

I tried with the following code snippet. It worked well. :-)

com.sun.org.apache.xml.internal.security.utils.Base64.encode("The string to encode goes here");
Bielefeld answered 4/3, 2015 at 12:27 Comment(0)
H
2
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;
}
Hawkie answered 25/2, 2020 at 8:58 Comment(0)
O
1

GZIP + Base64

The length of the string in a Base64 format is greater then original: 133% on average. So it makes sense to first compress it with GZIP, and then encode to Base64. It gives a reduction of up to 77% for strings greater than 200 characters and more. Example:

public static void main(String[] args) throws IOException {
    byte[] original = randomString(100).getBytes(StandardCharsets.UTF_8);

    byte[] base64 = encodeToBase64(original);
    byte[] gzipToBase64 = encodeToBase64(encodeToGZIP(original));

    byte[] fromBase64 = decodeFromBase64(base64);
    byte[] fromBase64Gzip = decodeFromGZIP(decodeFromBase64(gzipToBase64));

    // test
    System.out.println("Original: " + original.length + " bytes, 100%");
    System.out.println("Base64: " + base64.length + " bytes, "
            + (base64.length * 100 / original.length) + "%");
    System.out.println("GZIP+Base64: " + gzipToBase64.length + " bytes, "
            + (gzipToBase64.length * 100 / original.length) + "%");

    //Original: 3700 bytes, 100%
    //Base64: 4936 bytes, 133%
    //GZIP+Base64: 2868 bytes, 77%

    System.out.println(Arrays.equals(original, fromBase64)); // true
    System.out.println(Arrays.equals(original, fromBase64Gzip)); // true
}
public static byte[] decodeFromBase64(byte[] arr) {
    return Base64.getDecoder().decode(arr);
}

public static byte[] encodeToBase64(byte[] arr) {
    return Base64.getEncoder().encode(arr);
}
public static byte[] decodeFromGZIP(byte[] arr) throws IOException {
    ByteArrayInputStream bais = new ByteArrayInputStream(arr);
    GZIPInputStream gzip = new GZIPInputStream(bais);
    return gzip.readAllBytes();
}

public static byte[] encodeToGZIP(byte[] arr) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    GZIPOutputStream gzip = new GZIPOutputStream(baos);
    gzip.write(arr);
    gzip.finish();
    return baos.toByteArray();
}
public static String randomString(int count) {
    StringBuilder str = new StringBuilder();
    for (int i = 0; i < count; i++) {
        str.append(" ").append(UUID.randomUUID().toString());
    }
    return str.toString();
}

See also: How to get the JAR file for sun.misc.BASE64Encoder class?

Oscillatory answered 27/2, 2021 at 21:33 Comment(0)
H
0

add this library into your app level dependancies

implementation 'org.apache.commons:commons-collections4:4.4'

Hothead answered 16/2, 2021 at 7:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.