1. Overview
In this quick tutorial, we're going to learn how to write a Java InputStream to a Java OutputStream. We'll first use core functionality from Java 8 and Java 9. Then, we'll look at a couple of external libraries — Guava and the Apache Commons IO library.
The utility methods provided by Java 9, Guava, and Apache Commons IO do not flush or close the streams. So, we'll need to manage these resources by using try-with-resources or a finally block.
2. Using Java 8
First, we'll begin by creating a simple method using vanilla Java to copy the content from the InputStream to the OutputStream:
void copy(InputStream source, OutputStream target) throws IOException { byte[] buf = new byte[8192]; int length; while ((length = source.read(buf)) > 0) { target.write(buf, 0, length); } }
This code is pretty straightforward — we're simply reading in some bytes and then writing them out.
3. Using Java 9
Java 9 provides a utility method, InputStream.transferTo(), for this task.
Let's look at how we would use the transferTo() method:
@Test public void givenUsingJavaNine_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException { String initialString = "Hello World!"; try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes()); ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) { inputStream.transferTo(targetStream); assertEquals(initialString, new String(targetStream.toByteArray())); } }
Note that when working with file streams, it's more efficient to use Files.copy() than the transferTo() method.
4. Using Guava
Next, let's look at how we would use Guava's utility method ByteStreams.copy().
We'll need to include the guava dependency in our pom.xml:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>29.0-jre</version> </dependency>
Let's create a simple test case to show how we could use ByteStreams to copy data:
@Test public void givenUsingGuava_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException { String initialString = "Hello World!"; try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes()); ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) { ByteStreams.copy(inputStream, targetStream); assertEquals(initialString, new String(targetStream.toByteArray())); } }
5. Using Commons IO
Finally, let's look at how we would use the Commons IO IOUtils.copy() method for this task.
Of course, we'll need to add the commons-io dependency to the pom.xml:
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.7</version> </dependency>
Let's create a simple test case using IOUtils to copy data from the input stream to the output stream:
@Test public void givenUsingCommonsIO_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException { String initialString = "Hello World!"; try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes()); ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) { IOUtils.copy(inputStream, targetStream); assertEquals(initialString, new String(targetStream.toByteArray())); } }
Note: Commons IO provides additional methods for working with InputStreams and OutputStreams. IOUtils.copyLarge() should be used whenever it is necessary to copy 2 GB or more of data.
6. Conclusion
In this article, we explored simple ways to copy data from an InputStream to an OutputStream.
The implementation of these examples is available over on GitHub.