Get an OutputStream into a String

Viewed 691747

What's the best way to pipe the output from an java.io.OutputStream to a String in Java?

Say I have the method:

  writeToStream(Object o, OutputStream out)

Which writes certain data from the object to the given stream. However, I want to get this output into a String as easily as possible.

I'm considering writing a class like this (untested):

class StringOutputStream extends OutputStream {

  StringBuilder mBuf;

  public void write(int byte) throws IOException {
    mBuf.append((char) byte);
  }

  public String getString() {
    return mBuf.toString();
  }
}

But is there a better way? I only want to run a test!

6 Answers

I would use a ByteArrayOutputStream. And on finish you can call:

new String( baos.toByteArray(), codepage );

or better:

baos.toString( codepage );

For the String constructor, the codepage can be a String or an instance of java.nio.charset.Charset. A possible value is java.nio.charset.StandardCharsets.UTF_8.

The method toString() accepts only a String as a codepage parameter (stand Java 8).

I like the Apache Commons IO library. Take a look at its version of ByteArrayOutputStream, which has a toString(String enc) method as well as toByteArray(). Using existing and trusted components like the Commons project lets your code be smaller and easier to extend and repurpose.

This worked nicely

OutputStream output = new OutputStream() {
    private StringBuilder string = new StringBuilder();

    @Override
    public void write(int b) throws IOException {
        this.string.append((char) b );
    }

    //Netbeans IDE automatically overrides this toString()
    public String toString() {
        return this.string.toString();
    }
};

method call =>> marshaller.marshal( (Object) toWrite , (OutputStream) output);

then to print the string or get it just reference the "output" stream itself As an example, to print the string out to console =>> System.out.println(output);

FYI: my method call marshaller.marshal(Object,Outputstream) is for working with XML. It is irrelevant to this topic.

This is highly wasteful for productional use, there is a way too many conversion and it is a bit loose. This was just coded to prove to you that it is totally possible to create a custom OuputStream and output a string. But just go Horcrux7 way and all is good with merely two method calls.

And the world lives on another day....

Here's what I ended up doing:

Obj.writeToStream(toWrite, os);
try {
    String out = new String(os.toByteArray(), "UTF-8");
    assertTrue(out.contains("testString"));
} catch (UnsupportedEncondingException e) {
    fail("Caught exception: " + e.getMessage());
}

Where os is a ByteArrayOutputStream.

Here's what I did (don't use this in production, this is not great! But it makes fixing multiple errors easier.)

  • Create a list that holds Exceptions.

  • Create a logger to log exceptions.

  • Use the code below:

    private static void exceptionChecker() throws Exception { if(exceptionList.isEmpty()) return; //nothing to do :) great news

      //create lock for multithreading
      synchronized (System.err){
          //create new error stream
          ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
          PrintStream errorOut = new PrintStream(byteArrayOutputStream);
    
          //save standard err  out
          PrintStream standardErrOut = System.err;
    
          try{
              //set new error stream
              System.setErr(errorOut);
    
              exceptionList.forEach(exception -> {
                  exception.printStackTrace();
                  System.err.println("<---------->");
              });
    
    
          } finally {
              //reset everything back to normal
              System.setErr(standardErrOut);
    
              //Log all the exceptions
              exceptionLogger.warning(byteArrayOutputStream.toString());
    
              //throw final generic exception
              throw new Exception();
          }
      }}
    

This isn't great as you are throwing an error in the finally block and it locks on the error stream, but it works for dev purposes.

Related