Monday, January 14, 2013

Is there no WriterOutputStream in java ?

I have been wondering why there is no WriterOutputStream available in java.io package.  I was presented with a weird situation where there was a 3rd party API we had to live with ,which accepted only OutputStream , but forced to use the available PrintWriter which deals with text unlike byte streams. If you want to do the other way round its many to one mapping . See fig 1

       


So you just put strings , integers etc into the writer and behind the scenes they are just converted to stream of bytes. But when doing bytes to text you need to know what was the Character encoding used to represent the text as bytes, most often than not it is UTF-8 , assuming this we will go ahead and write a simple WriterOutputStream which will satiate the above said need (a stream wrapper for our writer) to specific extent.



 1 package javatest;
 2 
 3 import java.io.IOException;
 4 import java.io.OutputStream;
 5 import java.io.PrintWriter;
 6 
 7 /**
 8  * This class may blow up if your stream was encoded with different character code(than UTF-8)
 9  * in which case just re implement (extend this class or write your own) with
10  * a Character Decoder for the appropriate character set.
11  * @author srikalyc
12  */
13 public class WriterOutputStream extends OutputStream {
14     private PrintWriter writer;
15 
16     public WriterOutputStream(PrintWriter writer) {
17         this.writer = writer;
18     }
19 
20     /**
21      * Because only the lower order byte is used.
22      * @param b
23      * @throws IOException 
24      */
25     @Override
26     public void write(int b) throws IOException {
27         writer.write((byte)(b & 0x000000ff));
28     }
29 
30     @Override
31     public void write(byte[] b) throws IOException {
32         writer.append(new String(b));
33         flush();
34     }
35 
36     @Override
37     public void flush() throws IOException {
38         writer.flush();
39     }
40 
41     @Override
42     public void close() throws IOException {
43         writer.close();
44     }
45 
46     
47 }
48 
 
There are other ways to go about this as well, for smaller streams you could do something like this
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //Pass it to the 3rd party method which accepts only streams
        thirdPartyClass.method(baos) ;
        writer.println(baos.toString());


The baos acts like a nexus between the stream and text worlds. This could have been more efficiently
handled with ByteBuffers etc. Apache IO has a superb collection of Classes that does similar things in more extensive ways.