converting outputStream to byte array

34,220

Solution 1

From a theoretical perspective (i.e., irrespective of whether it makes sense in practice as a use case), this is an interesting question that essentially requires the implementation of a method like

public abstract byte[] convert(OutputStream out);

The Java OutputStream class, as its name implies, only supports an overridden write() method for I/O, and that write() method gets either an integer (representing 1 byte) or a byte array, the contents of which it sends to an output (e.g., a file).

For example, the following code saves the bytes already present in the data array, to the output.txt file:

byte[] data = ... // Get some data
OutputStream fos = new FileOutputStream("path/to/output.txt");
fos.write(data);

In order to get all the data that a given OutputStream will be outputting and put it into a byte array (i.e., into a byte[] object), the class from which the corresponding OutputStream object was instantiated, should keep storing all the bytes processed via its write() methods and provide a special method, such as toByteArray(), that would return them all, upon invocation.

This is exactly what the ByteArrayOutputStream class does, making the convert() method trivial (and unnecessary):

public byte[] convert(ByteArrayOutputStream out) {
  return out.toByteArray();
}

For any other type of OutputStream, not inherently supporting a similar conversion to a byte[] object, there is no way to make the conversion, before the OutputStream is drained, i.e. before the desired calls to its write() methods have been completed.

If such an assumption (of the writes to have been completed) can be made, and if the original OutputStream object can be replaced, then one option is to wrap it inside a delegate class that would essentially "grab" the bytes that would be supplied via its write() methods. For example:

public class DrainableOutputStream extends FilterOutputStream {
  private final ByteArrayOutputStream buffer;
  public DrainableOutputStream(OutputStream out) {
    super(out);
    this.buffer = new ByteArrayOutputStream();
  }
  @Override
  public void write(byte b[]) throws IOException {
    this.buffer.write(b);
    super.write(b);
  }
  @Override
  public void write(byte b[], int off, int len) throws IOException {
    this.buffer.write(b, off, len);
    super.write(b, off, len);
  }
  @Override
  public void write(int b) throws IOException {
    this.buffer.write(b);    
    super.write(b);
  }
  public byte[] toByteArray() {
    return this.buffer.toByteArray();
  }
}

The calls to the write() methods of the internal "buffer" (ByteArrayOutputStream) precede the calls to the original stream (which, in turn, can be accessed via super, or even via this.out, since the corresponding parameter of the FilterOutputStream is protected). This makes sure that the bytes will be buffered, even if there is an exception while writing to the original stream.

To reduce the overhead, the calls to super in the above class can be omitted - e.g., if only the "conversion" to a byte array is desired. Even the ByteArrayOutputStream or OutputStream classes can be used as parent classes, with a bit more work and some assumptions (e.g., about the reset() method).

In any case, enough memory has to be available for the draining to take place and for the toByteArray() method to work.

Solution 2

For @Obicere comment example:

ByteArrayOutputStream btOs = new ByteArrayOutputStream();
btOs.write("test bytes".getBytes());    
String restoredString = new String(btOs.toByteArray());
System.out.println(restoredString);
Share:
34,220
henri Dunand
Author by

henri Dunand

Updated on February 09, 2020

Comments

  • henri Dunand
    henri Dunand about 4 years

    How can I get the bytes of an outputStream, or how can I convert an outputStream to a byte array?

    • domsson
      domsson about 7 years
      Are you sure you are talking about an OutputStream and not an InputStream?
    • Obicere
      Obicere about 7 years
      ByteArrayOutputStream is what you're looking for.
    • henri Dunand
      henri Dunand about 7 years
      @domdom im talking about OutputStream
    • henri Dunand
      henri Dunand about 7 years
      @DumpCake i've been through that answer, but it did not fit with my needs
    • henri Dunand
      henri Dunand about 7 years
      @Obicere can you explain more ?
    • Obicere
      Obicere about 7 years
      That depends, what exactly are you trying to accomplish? What are your "needs"?
    • henri Dunand
      henri Dunand about 7 years
      @Obicere i have two methods, as output of the first one, i get an outputstream and as an input of my second method, i need to pass a byte array with the content of the outputStream. so, what i need is to convert the resulted output stream to a byte array
    • Obicere
      Obicere about 7 years
      Showing code will make this easier and will help portray what you are trying to accomplish.
  • henri Dunand
    henri Dunand about 7 years
    thank you for the extended explanations, it helps me to understand things better