import java.io.*;
import java.util.*;/**
 * This class implements a FilterInputStream that reads base64-encoded
 * data (as defined in RFC1521) from another InputStream and decodes
 * it while reading. 
 */
public class Base64InputStream extends FilterInputStream {    private int surplus;
    private int decoded;
    private int lastRead = 0;    /**
     * The constructor for the decoding input stream.
     *
     * @param in the underlying input stream
     */
    public Base64InputStream (InputStream in) {
super (in);
decoded = 0;
    }    /**
     * This method always return 0, as we really can't be sure about the
     * number of decoded bytes available without doing the decoding. Imaging
     * an underlying input stream from which several whitespace characters
     * can still be read. Thus calling available() on the underlying stream
     * returns a number greater than zero. But whitespace decodes to nothing,
     * so we can't derive a reliable number for available from he underlying
     * stream.
     */
    public int available () throws IOException {
return 0;
    }    /**
     * Always returns false, since ing is not supported.
     */
    public boolean Supported () {
return false;
    }    /**
     * Reads a single byte. Returns -1 if the input stream is exhausted.
     */
    public int read () throws IOException {
byte b[] = new byte[1];
int res = read (b);
if (res < 0)
    return res;
return (b[0] & 0xff);
    }    /**
     * Reads len bytes from the input stream, saving them in the array
     * data beginning at index off. 
     * Returns -1 if the input stream is exhausted.
     *
     * @param data the array with bytes having been read.
     * @param off the position of the first byte read within the array.
     * @param len the number of bytes to be read.
     */
    public int read (byte[] data, int off, int len) throws IOException {
int pos = off;
// EOF is EOF is EOF...
if (lastRead < 0)
    return -1; // get from buf while not on boundary
while (len > 0 && decoded > 0 && lastRead >= 0) {
    int b = decodeByte ();
    if (b < 0) {
break;
    }
    data[pos++] = (byte)b;
    len -= 1;
}
// shortcut while complete groups are requested
while (len >= 3 && lastRead >= 0) {
    int grp0 = 0, grp1 = 0, grp2 = 0, grp3 = 0;
    int gotCnt = 0;
    while (gotCnt < 4) {
lastRead = in.read ();
if (lastRead < 0)
    break;
if (lastRead == '=') {
    // end of encoded data
    if (gotCnt == 2) {
// a proper base64 sequence has a multiple of
// 4 characters, so another '=' should follow. Align.
in.read ();
    }
    lastRead = -1;
    break;
}
int grp = codedBits((char)lastRead);
if (grp >= 0) {
    switch (gotCnt++) {
    case 0:
grp0 = grp;
break;
    case 1:
grp1 = grp;
break;
    case 2:
grp2 = grp;
break;
    case 3:
grp3 = grp;
break;
    }
}
    }
    switch (gotCnt) {
    case 4:
data[pos + 2] = (byte)((grp2 << 6) | (grp3));
    case 3:
data[pos + 1] = (byte)((grp1 << 4) | (grp2 >>> 2));
    case 2:
data[pos] = (byte)((grp0 << 2) | (grp1 >>> 4));
pos += (gotCnt - 1);
len -= (gotCnt - 1);
    }
}
// get rest of requested input
while (len > 0 && lastRead >= 0) {
    int b = decodeByte ();
    if (b < 0) {
break;
    }
    data[pos++] = (byte)b;
    len -= 1;
}
if (len > 0 && pos == off)
    return -1;
return pos - off;
    }    private int decodeByte () throws IOException {
int b;
switch (decoded) {
case 0:
    do {
lastRead = in.read ();
if (lastRead < 0 || lastRead == '=') {
    lastRead = -1;
    return -1;
}
    } while ((b = codedBits ((char)lastRead)) < 0);
    b = (b << 2);
    do {
lastRead = in.read ();
if (lastRead < 0 || lastRead == '=') {
    lastRead = -1;
    return -1;
}
    } while ((surplus = codedBits ((char)lastRead)) < 0);
    b = b | (surplus >>> 4);
    surplus = (surplus & 0xf);
    decoded = 1;
    return b; case 1:
    b = (surplus << 4);
    do {
lastRead = in.read ();
if (lastRead < 0 || lastRead == '=') {
    if (lastRead == '=') {
// a proper base64 sequence has a multiple of
// 4 characters, so another '=' should follow. Align.
in.read ();
    }
    lastRead = -1;
    return -1;
}
    } while ((surplus = codedBits ((char)lastRead)) < 0);
    b = b | (surplus >>> 2);
    surplus = (surplus & 0x3);
    decoded = 2;     
    return b; case 2:
    b = (surplus << 6);
    do {
lastRead = in.read ();
if (lastRead < 0 || lastRead == '=') {
    lastRead = -1;
    return -1;
}
    } while ((surplus = codedBits ((char)lastRead)) < 0);
    b = b | surplus;
    decoded = 0;
    return b;
}
// never realastReaded, but compiler can't know and complains
return -1;
    }    private int codedBits (char c) {
if ('A' <= c && c <= 'Z')
    return c - 'A';
if ('a' <= c && c <= 'z')
    return c - 'a' + 26;
if ('0' <= c && c <= '9')
    return c - '0' + 52;
if (c == '+')
    return 62;
if (c == '/')
    return 63;
return -1;
    }
}

解决方案 »

  1.   

    再来一个输出流的:
    import java.io.*;
    import java.util.*;/**
     * This class implements a FilterOutputStream that writes base64-encoded
     * data (as defined in RFC1521) to an underlying OutputStream, encoding the
     * data while it is being written.
     *
     * Note that this implementation does not attempt to do any canonalization.
     * I.e. if used to encode text in an RFC1521 conformant way, care must be 
     * taken to convert line breaks
     * to CRLF before passing the data to the Base64OutputStream. The lack of
     * canonalization is considered a feature as it allows the
     * Base64OutputStream to be used for binary data. (Maybe one day I'll add
     * a TextCanonalizationOutputStream.)
     */
    public class Base64OutputStream extends FilterOutputStream {    private final static char charCodes[] = {
    'A','B','C','D','E','F','G','H',
    'I','J','K','L','M','N','O','P',
    'Q','R','S','T','U','V','W','X',
    'Y','Z','a','b','c','d','e','f',
    'g','h','i','j','k','l','m','n',
    'o','p','q','r','s','t','u','v',
    'w','x','y','z','0','1','2','3',
    '4','5','6','7','8','9','+','/'
    };    private byte encBuf[] = new byte[4];
        private int encoded;
        private int surplus;
        private int col;
        private boolean finishOnFlush;    /**
         * The constructor for the encoding output stream.
         *
         * @param out the underlying output stream.
         * @param finishOnFlush controls the behaviour of the flush method.
         * 
         * @see org.tsx.mnl.io.base64.Base64OutputStream#flush
         */
        public Base64OutputStream (OutputStream out, boolean finishOnFlush) {
    super (out);
    encoded = 0;
    col = 0;
    this.finishOnFlush = finishOnFlush;
        }    /**
         * Sets the value of finishOnFlush.
         *
         * @param value the new value.
         * 
         * @see org.tsx.mnl.io.base64.Base64OutputStream#flush
         */
        public void setFinishOnFlush (boolean value) {
    finishOnFlush = value;
        }    /**
         * Encodes and writes a single byte to the output stream.
         *
         * @param b the byte to be written.
         */
        public void write (int b) throws IOException {
    byte a[] = { (byte)(b & 0xff) };
    write (a, 0, 1);
        }    /**
         * Encodes and writes len bytes from array data to the outputstream, 
         * starting with the byte at position off.
         *
         * @param data the array holding the bytes to be written.
         * @param off the position off the first byte to be written within the 
         * array.
         * @param len the number of bytes to be written.
         */
        public void write (byte[] data, int off, int len) throws IOException {
    int pos = off;
    // fill encBuf if possible
    while (encoded > 0 && pos < off + len) {
        encodeByte (data[pos]);
        pos += 1;
    }
    // encode triples for efficiency
    while (pos + 2 < off + len) {
        byte b0 = data[pos];
        byte b1 = data[pos + 1];
        byte b2 = data[pos + 2];
        encBuf[0] = (byte)charCodes[((b0 >> 2) & 0x3f)];
        encBuf[1] = (byte)charCodes[((b0 & 0x3) << 4)|((b1 >> 4) & 0xf)];
        encBuf[2] = (byte)charCodes[((b1 & 0xf) << 2)|((b2 >> 6) & 0x3)];
        encBuf[3] = (byte)charCodes[b2 & 0x3f];
        out.write (encBuf);
        encoded = 0;
        col += 4;
        if (col >= 76) {
    out.write ('\n');
    col = 0;
        }
        pos += 3;
    }
    // encode rest
    while (pos < off + len) {
        encodeByte (data[pos]);
        pos += 1;
    }
        }    private void encodeByte (byte b) throws IOException {
    switch (encoded) {
    case 0: 
        encBuf[0] = (byte)charCodes[(b >> 2) & 0x3f];
        surplus = ((b & 0x3) << 4);
        encBuf[1] = (byte)charCodes[surplus];
        encoded += 1;
        break;
    case 1:
        encBuf[1] = (byte)charCodes[surplus | ((b >> 4) & 0xf)];
        surplus = ((b & 0xf) << 2);
        encBuf[2] = (byte)charCodes[surplus];
        encoded += 1;
        break;
    case 2:
        encBuf[2] = (byte)charCodes[surplus | ((b >>> 6) & 0x3)];
        encBuf[3] = (byte)charCodes[b & 0x3f];
        out.write (encBuf);
        encoded = 0;
        col += 4;
        if (col >= 76) {
    out.write ('\n');
    col = 0;
        }
        break;
    }
        }    /**
         * This method is to write all buffered data to its destination.
         * With a base64 encoding there arises a problem: if an encoding character
         * isn't completly known yet because its value depends partially
         * on the last byte written and partially on the next byte to be
         * written, then flush can't write it without assuming that there
         * will be no more bytes coming. 
         * 
         * The behaviour for flush can therefore
         * be controlled by the flag finishOnFlush when the stream is created. 
         * If the flag is set, flush will assume that no more data is to be
         * written after flush has been called, thus effectivly finishing the
         * stream of encoded data. This behaviour is especially useful, when
         * the Base64OutputStream is created with an underlying output stream 
         * that contains mixed
         * content. In this case, we cannot call close on the Base64OutputStream
         * because this would make the underlying OutputStream unusable as well.
         *
         * @see org.tsx.mnl.io.base64.Base64OutputStream
         * @see java.io.OutputStream#flush
         */
        public void flush () throws IOException {
    if (finishOnFlush)
        doFlush ();
        }    private void doFlush () throws IOException {
    switch (encoded) {
    case 1:
        encBuf[2] = (byte)'=';
    case 2:
        encBuf[3] = (byte)'=';
        out.write (encBuf);
        col += 4;
        break;
    }
    if (col > 0) {
        out.write ('\n');
        col = 0;
    }
        }    /**
         * This method finishes the encoded stream and calls close on the
         * underlying output stream.
         */
        public void close () throws IOException {
    doFlush ();
    out.close ();
        }
    }
      

  2.   

    这是用法:
    import java.io.*;class Test {    public static void main(String[] args) { try {
        Base64OutputStream enc
    = new Base64OutputStream (System.out, false);
        OutputStreamWriter out = new OutputStreamWriter (enc);
        String s = "Hello world!\n\n";
        s = s + "While normally the short message above is sufficient\n";
        s = s + "for a test, we need more text in order to get another\n";
        s = s + "line of output.\n";

        out.write (s, 0, s.length());
        enc.setFinishOnFlush (true);
        out.flush ();     FileInputStream data = new FileInputStream ("data.base64");
        InputStream dec = new Base64InputStream (data);
        System.out.print ((char)dec.read ());
        byte[] b = new byte[16];
        int cnt;
        while ((cnt = dec.read (b)) >= 0)
    System.out.print (new String (b, 0, cnt));
        System.out.print ("Besides the base64 data, input contains: ");
        while ((cnt = data.read ()) >= 0)
    System.out.print ((char)cnt);
    } catch (Exception e) {
        System.out.println ("Error: " + e.getMessage());
                e.printStackTrace();
    }
        }
    }