41

I need to put the contents of a java.nio.ByteBuffer into an java.io.OutputStream. (wish I had a Channel instead but I don't) What's the best way to do this?

I can't use the ByteBuffer's array() method since it can be a read-only buffer.

I also may be interspersing writes to the OutputStream between using this ByteBuffer and having a regular array of byte[] which I can with use OutputStream.write() directly.

Jonas
  • 121,568
  • 97
  • 310
  • 388
Jason S
  • 184,598
  • 164
  • 608
  • 970

1 Answers1

65

Look at Channels.newChannel(OutputStream). It will give you a channel given an OutputStream. With the WritableByteChannel adapter you can provide the ByteBuffer which will write it to the OutputStream.

public void writeBuffer(ByteBuffer buffer, OutputStream stream) {
   WritableByteChannel channel = Channels.newChannel(stream);

   channel.write(buffer);
}

This should do the trick!

forgivenson
  • 4,394
  • 2
  • 19
  • 28
ng.
  • 7,099
  • 1
  • 38
  • 42
  • if I keep the channel as well as the stream, can I intermix calls to both? – Jason S Feb 23 '09 at 22:26
  • Ya, sure can, reduces the cost of creating the channel every time :) – ng. Feb 23 '09 at 22:28
  • 10
    Note that this approach involves copying from the ByteBuffer into a temporary array that is then written to the OutputStream. If performance is important, you may need to do a bit of refactoring to avoid unnecessary block copies. – Trevor Robinson Aug 14 '12 at 22:09
  • @trevor-robinson, could you expand on that comment? Why is a copy involved? How can it be avoided? – Frederik Feb 13 '15 at 16:12
  • 7
    @Frederik, `OutputStream` itself only accepts byte arrays, and since `ByteBuffer.array()` may not be supported, a copy is the only way in general. As a special case, the Oracle/OpenJDK `Channels.newChannel` impl does check if the stream is (exactly) a `FileOutputStream`, which has a real native channel; otherwise, it returns an adapter (`Channels.WritableByteChannelImpl`) that copies from the buffer to an array in up to 8KB chunks. The only way to avoid this is to use channels throughout. You have to architect for NIO to get the perf benefits. – Trevor Robinson Feb 13 '15 at 21:35
  • It's a shame you have to go through these hoops when using `java.net.http.WebSocket`, in which data is delivered in `ByteBuffer` chunks that you have to chain together to do anything useful. Those bytebuffers wrap a much larger array with an offset, so you have to be careful when going that route. – Mark Jeronimus Dec 21 '22 at 16:06