Table of Contents
1. Overview
In this quick tutorial, we’re going to take a look at how to convert an InputStream to a byte[] and ByteBuffer – first using plain Java, then using Guava and Commons IO.
This article is part of the “Java – Back to Basic” series here on VietMX’s Blog.
2. Convert to Byte Array
Let’s look at obtaining a byte array from simple input streams. The important aspect of a byte array is that it enables an indexed (fast) access to each 8-bit (a byte) value stored in memory. Hence, you can manipulate these bytes to control each bit. We are going to take a look at how to convert a simple input stream to a byte[] – first using plain Java, then using Guava and Apache Commons IO.
2.1. Convert Using Plain Java
Let’s start with a Java solution focused on dealing with a fixed size stream:
@Test public void givenUsingPlainJavaOnFixedSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); byte[] targetArray = new byte[is.available()]; is.read(targetArray); }
In the case of a buffered stream – where we’re dealing with a buffered stream and don’t know the exact size of the underlying data, we need to make the implementation more flexible:
@Test public void givenUsingPlainJavaOnUnknownSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5, 6 }); // not really known ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int nRead; byte[] data = new byte[4]; while ((nRead = is.read(data, 0, data.length)) != -1) { buffer.write(data, 0, nRead); } buffer.flush(); byte[] targetArray = buffer.toByteArray(); }
Starting with Java 9, we can achieve the same with a dedicated readNbytes method:
@Test public void givenUsingPlainJava9OnUnknownSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5, 6 }); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int nRead; byte[] data = new byte[4]; while ((nRead = is.readNBytes(data, 0, data.length)) != 0) { System.out.println("here " + nRead); buffer.write(data, 0, nRead); } buffer.flush(); byte[] targetArray = buffer.toByteArray(); }
The difference between these two methods is very subtle.
The first one, read(byte[] b, int off, int len), reads up to len bytes of data from the input stream, whereas the second one, readNBytes(byte[] b, int off, int len), reads exactly the requested number of bytes.
Additionally, read returns -1 if there’s no more data available in the input stream. readNbytes, however, always returns the actual number of bytes read into the buffer.
We can also read all the bytes at once:
@Test public void givenUsingPlainJava9_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); byte[] data = is.readAllBytes(); }
2.2. Convert Using Guava
Let’s now look at the simple Guava based solution – using the convenient ByteStreams utility class:
@Test public void givenUsingGuava_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { InputStream initialStream = ByteSource.wrap(new byte[] { 0, 1, 2 }).openStream(); byte[] targetArray = ByteStreams.toByteArray(initialStream); }
2.3. Convert Using Commons IO
And finally – a straightforward solution using Apache Commons IO:
@Test public void givenUsingCommonsIO_whenConvertingAnInputStreamToAByteArray_thenCorrect() throws IOException { ByteArrayInputStream initialStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); byte[] targetArray = IOUtils.toByteArray(initialStream); }
The method IOUtils.toByteArray() buffers the input internally, so there is no need to use a BufferedInputStream instance when buffering is needed.
3. Convert to ByteBuffer
Now, let’s look at obtaining a ByteBuffer from an InputStream. This is useful whenever we need to do fast and direct low-level I/O operations in memory.
Using the same approach as the above sections, we’re going to take a look at how to convert an InputStream to a ByteBuffer – first using plain Java, then using Guava and Commons IO.
3.1. Convert Using Plain Java
In the case of a byte stream – we know the exact size of the underlying data. Let’s use the ByteArrayInputStream#available method to read the byte stream into a ByteBuffer:
@Test public void givenUsingCoreClasses_whenByteArrayInputStreamToAByteBuffer_thenLengthMustMatch() throws IOException { byte[] input = new byte[] { 0, 1, 2 }; InputStream initialStream = new ByteArrayInputStream(input); ByteBuffer byteBuffer = ByteBuffer.allocate(3); while (initialStream.available() > 0) { byteBuffer.put((byte) initialStream.read()); } assertEquals(byteBuffer.position(), input.length); }
3.2. Convert Using Guava
Let’s now look at a simple Guava-based solution – using the convenient ByteStreams utility class:
@Test public void givenUsingGuava__whenByteArrayInputStreamToAByteBuffer_thenLengthMustMatch() throws IOException { InputStream initialStream = ByteSource .wrap(new byte[] { 0, 1, 2 }) .openStream(); byte[] targetArray = ByteStreams.toByteArray(initialStream); ByteBuffer bufferByte = ByteBuffer.wrap(targetArray); while (bufferByte.hasRemaining()) { bufferByte.get(); } assertEquals(bufferByte.position(), targetArray.length); }
Here we use a while loop with the method hasRemaining to show a different way to read all the bytes into the ByteBuffer. Otherwise, the assertion would fail because the ByteBuffer index position will be zero.
3.3. Convert Using Commons IO
And finally – using Apache Commons IO and the IOUtils class:
@Test public void givenUsingCommonsIo_whenByteArrayInputStreamToAByteBuffer_thenLengthMustMatch() throws IOException { byte[] input = new byte[] { 0, 1, 2 }; InputStream initialStream = new ByteArrayInputStream(input); ByteBuffer byteBuffer = ByteBuffer.allocate(3); ReadableByteChannel channel = newChannel(initialStream); IOUtils.readFully(channel, byteBuffer); assertEquals(byteBuffer.position(), input.length); }
4. Conclusion
This article illustrated various ways to convert a raw input stream to a byte array and a ByteBuffer using plain Java, Guava, and Apache Commons IO.
The implementation of all these examples can be found in our GitHub project.