Java Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

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 Baeldung.

Further reading:

Introduction to Spring’s StreamUtils

Discover Spring's StreamUtils class.

Read more

Introduction to Java Serialization

We learn how to serialize and deserialize objects in Java.

Read more

Java String Conversions

Quick and practical examples focused on converting String objects to different data types in Java.

Read more

2. Convert to Byte Array

Let’s look at obtaining a byte array from simple input streamsThe 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 givenUsingPlainJava_whenConvertingAnInputStreamToAByteArray_thenCorrect() 
  throws IOException {
    InputStream initialStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 });

    byte[] targetArray = new byte[initialStream.available()];
    initialStream.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 }); // not really unknown

    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    int nRead;
    byte[] data = new byte[1024];
    while ((nRead = is.read(data, 0, data.length)) != -1) {
        buffer.write(data, 0, nRead);
    }

    buffer.flush();
    byte[] byteArray = buffer.toByteArray();
}

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.

Java bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

newest oldest most voted
Notify of
Matthieu Wipliez
Guest

Please note that the example in “plain Java” only works in this case because the ByteArrayInputStream’s implementation of “available” will return the exact number of bytes in the byte array that’s backing it. However, in a general stream this is not the case, because most streams are actually buffered, so available only returns a subset of the total number of bytes. That’s why you should not rely on “available” but instead use a loop and rely on the number of bytes really read, as returned by read(byte[]).

Eugen Paraschiv
Guest

Hey Matthieu – nice catch, I updated the article to clearly differentiate these 2 scenarios. Cheers,
Eugen.

Octavian
Guest

One thing I find “not specified enough” is that most of these routines do not close the provided InputStream (the official javadocs included). Of course, this makes all the sense in the world since it’s not necessarily the copying routine’s responsibility to close the argument.

However, all too often I see, sprinkled through the projects I am involved with, copy-pasted snippets of code without proper resource management…

Eugen Paraschiv
Guest

Hey Octavian,
Yeah – I fully agree, not closing these kinds of low level resources leads to hard to pin-point memory leaks. These are just tests and kept simple on purposes, but yes, in production code you always need to make sure you clean these up. Cheers,
Eugen.