The topoc today is about a samll change - finally, Java 8 added the Base64 encodder/decoder into the
java.util package. Although Base64 increases the actual data transmission length, in the plain-text Internet protocols, Base64 is commonly used to encode the binary data as text (e.g, MIME email). Therefore, it is surprised that the Base64 support is added until Java 8. Before Java 8, it needs the third-party library, for example, Apache Commons Codec, to provide Base64 encoder and decoder.
In the past work, I was developing a system X, a job is to receive the user uploaded file A. For some reason, system X does not have the capacity for storing files, and the uploaded file is actually stored in another system Y that provides file content indexing. Another similar job is that when the user downloads a (machine generated) file B from the system X, the file is also stored in the system Y for auditing. Both the system X and the system Y are RESTful Web Service. The file content transmitting through HTTP between the system X and the system Y is Base64 encoded as text in a JSON object. And the enocder and decoder I used is Apache Commons Codec.
Since Java 8 includes the Base64 encoder and decoder, it's time to write some codes with the encoder and decoder. However, using the
IOUils.copy(InputStream, OutputStream) method in Apache Commons IO to handle reading something from input and putting the data into output is my personal habit. If the Apache Commons IO is not used, the helper method in Code List 1 is usefaul - writing while loop to copy data from the input to output is not needed any more.
With the helper method, the first program uses Base64 encoder to enocde the data from the
InputStream and then write the encoded data into the
OutputStream. In Code List 2, the
encode(InputStream, OutputStream, Base64.Encoder) method accepts three parameters. The first is the data source and the second is the encoded data destination. These two are easy to understand, but how about the third parameter? Why do I have to specify the encoder? Are there different kinds of Base64 encoders? Yes! Base64 has variants in different protocols. Java 8 provides three kinds of Base64 encoders/decoders. The first kind is the basic (using
Base64.getDecoder() to get the basic encoder and decoder, respectively) which only uses
= alphabet to perform encoding, and the content is not line-separated. The second kind is the URL and Filename safe (using
Base64.getUrlDecoder() to get the encoder and decoder). Since the symbols
/ have special usages in the URL, and
/ is illegal to use as filename in many filesystems, the encoder uses
- (minus) to replace
+ and uses
_ (underline) to replace
/. The third kind is MIME (using
Base64.getMimeDecoder() to get the encoder and decoder, respectively) which uses the same alphabet as the basic, but adding
\r\n after every 76 characters for line-separation. Assume that the basic is commonly used, a method without the third parameter like Code List 2 can be provided for convenient.
After encoding, a decoder can be used to decode the data. In Code List 3, the
decode(InputStream, OutputStream, Base64.Decoder) method also accepts three parameters: the first is the encoded data source, the second is the decoded data destination, and the third is the decoder. The three kinds of encoders/decoders mentioned above can not be used hybridly. That is the content encoded with the basic encoder can only be decoded with the basic decoder. The same, a method without the third parameter can be provided for convenient, and in the the following examples, the convenient version with the basic encoder/decoder is not listed for space saving.
With the method that encodes or decodes the content reading from the
InputStream and then writes the encoded or decoded data into the
OutputStream, variant can be provided for different usages. For example, in Code List 4, the method accepts two files as the input and output. In the method, the files are wrapped by
FileOutputStream and can be fed as the parameters of the methods in Code List 2 and Code List 3 to perform encoding or decoding operation.
Well, the encoded or decoded content is not always written into a file. In the job experience mentioned above, the file content is encoded as a part of the JSON object. For that case, the method in Code List 5 is useful - encoding the file content as a string. The method uses
ByteArrayOutputStream as the buffer to store the encoded or decoded bytes, and then call
toString(String) to output the content as a string.
The same, the data source may not be a file - a string is also possible. For the case, the method in Code List 6 can be used. The method uses
getBytes() to obtain the string content as a byte array and wraps the byte array with
ByteArrayInputStream as the input stream, and then feeds the input stream and the output stream for encoding or decoding operation.
Java 8 includes the Base64 encoder and decoder to provide convenience. However, the third-party libraries like Apache Commons Codec usually provide many kinds of encoders and decoders more than Base64 - that is much more convenient. But if your application only needs Base64 encoder and decoder, in the Java 8 environment, the third-party library for Base64 encoder and decoder is not required. Well, only in the Java 8 environment, therefore, using the built-in Base64 encoder and decoder becomes a design trade-off.
Puzzle: try to decode the file (tip: the file is a PNG picture.)