views:

353

answers:

3

I need to write string containing base64 encoded text to a text file and then later read that string back from the text file to a string variable.

How can i do it so that there is no data loss due to encoding issues?

+2  A: 

Base64 is only A–Z, a–z, 0–9, + and /. So there should be no encoding problem. As long as you're able to encode Ascii properly. Base64 was invented to represent bytes in 7-bit characters.

To encode and decode you can use commons codec Base64.

Thomas Jung
+1  A: 

Base64 Encoder :

// Sample program to encode a binary file into a Base64 text file.
// Author: Christian d'Heureuse (www.source-code.biz)

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.IOException;

public class Base64FileEncoder {

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

private static void encodeFile (String inputFileName, String outputFileName) throws IOException {
   BufferedInputStream in = null;
   BufferedWriter out = null;
   try {
      in = new BufferedInputStream(new FileInputStream(inputFileName));
      out = new BufferedWriter(new FileWriter(outputFileName));
      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, len));
      out.newLine(); }}

} // end class Base64FileEncoder

Base64 Decoder :

// Sample program to decode a Base64 text file into a binary file.
// Author: Christian d'Heureuse (www.source-code.biz)

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;

public class Base64FileDecoder {

public static void main (String args[]) throws IOException {
   if (args.length != 2) {
      System.out.println ("Command line parameters: inputFileName outputFileName");
      System.exit (9); }
   decodeFile (args[0], args[1]); }

private static void decodeFile (String inputFileName, String outputFileName) throws IOException {
   BufferedReader in = null;
   BufferedOutputStream out = null;
   try {
      in = new BufferedReader(new FileReader(inputFileName));
      out = new BufferedOutputStream(new FileOutputStream(outputFileName));
      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.decode(s);
      out.write (buf); }}

} // end class Base64FileDecoder

Test Base64 Coder :

// Test program for the Base64Coder class.

public class TestBase64Coder {

    public static void main (String args[]) throws Exception {
       System.out.println ("TestBase64Coder started");
       test1();
       test2();
       System.out.println ("TestBase64Coder completed"); }

    // Test Base64Coder with constant strings.
    private static void test1() {
       System.out.println ("test1 started");
       check ("Aladdin:open sesame", "QWxhZGRpbjpvcGVuIHNlc2FtZQ==");  // example from RFC 2617
       check ("", "");
       check ("1", "MQ==");
       check ("22", "MjI=");
       check ("333", "MzMz");
       check ("4444", "NDQ0NA==");
       check ("55555", "NTU1NTU=");
       check ("abc:def", "YWJjOmRlZg==");
       System.out.println ("test1 completed"); }

    private static void check (String plainText, String base64Text) {
       String s1 = Base64Coder.encodeString(plainText);
       String s2 = Base64Coder.decodeString(base64Text);
       if (!s1.equals(base64Text) || !s2.equals(plainText))
          System.out.println ("check failed for \""+plainText+"\" / \""+base64Text+"\"."); }

    // Test Base64Coder against sun.misc.BASE64Encoder/Decoder with
    // random strings.
    private static void test2() throws Exception {
       System.out.println ("test2 started");
       sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
       sun.misc.BASE64Decoder dec = new sun.misc.BASE64Decoder();
       java.util.Random rnd = new java.util.Random(0x538afb92);
       for (int i=0; i<50000; i++) {
          int len = rnd.nextInt(55);
          byte[] b0 = new byte[len];
          rnd.nextBytes(b0);
          String e1 = new String(Base64Coder.encode(b0));
          String e2 = enc.encode(b0);
          if (!e1.equals(e2)) System.out.println ("Error\ne1=" + e1 + " len=" + e1.length() + "\ne2=" + e2 + " len=" + e2.length());
          byte[] b1 = Base64Coder.decode(e1);
          byte[] b2 = dec.decodeBuffer(e2);
          if (!compareByteArrays(b1, b0) || !compareByteArrays(b2, b0))
             System.out.println ("Decoded data not equal. len1=" + b1.length + " len2=" + b2.length); }
       System.out.println ("test2 completed"); }

    // Compares two byte arrays.
    private static boolean compareByteArrays (byte[] a1, byte[] a2) {
       if (a1.length != a2.length) return false;
       for (int p=0; p<a1.length; p++)
          if (a1[p] != a2[p]) return false;
       return true; }

    } // end class TestBase64Coder
SjB
A: 

There is a sun class that will do it for you (although it will generate compiler warnings:

import sun.misc.BASE64Encoder;

BASE64Encoder encoder = new BASE64Encoder();

String toEncode = "encodeMe";

String encoded = encodeBuffer(toEncode.getBytes());

From memory, there's also a BASE64Decoder, but I've not used that, I only go one way for comparison of usernames over-the-wire.

James B
Let's start the good old portability discussion, again. Javac: A.java:1: warning: sun.misc.BASE64Encoder is Sun proprietary API and may be remo ved in a future release
Thomas Jung
There is also com.sun.org.apache.xerces.internal.impl.dv.util.Base64, which will not generate warning.
ZZ Coder
Fair enough, it's easy to forget about portability when I only have internal customers and one platform for my software line.
James B