Java
Coding
OutputStream
InputStream
Data Conversion

How do I convert an OutputStream to an InputStream?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Java, you do not truly convert a generic OutputStream into an InputStream. An OutputStream is a destination for bytes, while an InputStream is a source of bytes. What you actually do is either capture the written bytes so they can be read back later, or connect a writing stream to a reading stream with a pipe.

The Common Buffered Case

If the bytes are small enough to fit in memory, the normal pattern is:

  1. write into a ByteArrayOutputStream
  2. call toByteArray()
  3. wrap the result in a ByteArrayInputStream
java
1import java.io.ByteArrayInputStream;
2import java.io.ByteArrayOutputStream;
3import java.nio.charset.StandardCharsets;
4
5public class BufferExample {
6    public static void main(String[] args) throws Exception {
7        ByteArrayOutputStream out = new ByteArrayOutputStream();
8        out.write("hello stream".getBytes(StandardCharsets.UTF_8));
9
10        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
11        System.out.println(new String(in.readAllBytes(), StandardCharsets.UTF_8));
12    }
13}

This is the easiest answer when the data is already complete and comfortably memory-sized.

Why It Is Not a Generic Conversion

This works only because ByteArrayOutputStream stores bytes in memory and exposes them back as a byte array. A generic OutputStream does not necessarily keep anything readable afterward.

For example:

  • a FileOutputStream writes to a file
  • a socket output stream writes to the network
  • a servlet output stream writes to a client response

Those are destinations, not reusable in-memory buffers. So if you need an InputStream later, design for that upfront instead of hoping to reverse the stream type later.

The Streaming Case: Use Piped Streams

If you need one part of your program to write bytes while another part reads them immediately, use PipedOutputStream and PipedInputStream.

java
1import java.io.PipedInputStream;
2import java.io.PipedOutputStream;
3import java.nio.charset.StandardCharsets;
4
5public class PipeExample {
6    public static void main(String[] args) throws Exception {
7        PipedOutputStream out = new PipedOutputStream();
8        PipedInputStream in = new PipedInputStream(out);
9
10        Thread writer = new Thread(() -> {
11            try {
12                out.write("streamed data".getBytes(StandardCharsets.UTF_8));
13                out.close();
14            } catch (Exception e) {
15                throw new RuntimeException(e);
16            }
17        });
18
19        writer.start();
20        System.out.println(new String(in.readAllBytes(), StandardCharsets.UTF_8));
21        writer.join();
22    }
23}

This is not conversion either. It is a producer-consumer connection between two different stream types.

Sometimes the Real Answer Is a File

If the data is too large for memory and you do not want a pipe, writing to a temporary file and then opening a FileInputStream may be the most practical solution. That is slower than in-memory buffering, but it is often simpler than trying to manage large byte arrays.

So the design choice depends on the data size and timing:

  • small and complete now: byte array buffering
  • produced and consumed concurrently: piped streams
  • large and durable: temp file

Another useful rule is to separate API shape from storage shape. If an API requires an InputStream, it is often simpler to design your code around a readable source from the beginning instead of writing to an arbitrary sink first and then trying to reverse the flow.

Common Pitfalls

  • Assuming every OutputStream can somehow be turned into a readable stream after writing.
  • Using ByteArrayOutputStream for very large data and exhausting heap memory.
  • Using piped streams without considering threading and blocking behavior.
  • Forgetting to close or flush the writer before expecting the reader to see all data.
  • Solving a file-backed problem with a memory-only design when a temp file would be simpler.

Summary

  • You do not directly convert a generic OutputStream into an InputStream.
  • For in-memory data, use ByteArrayOutputStream plus ByteArrayInputStream.
  • For live producer-consumer flow, use PipedOutputStream and PipedInputStream.
  • For large data, a temporary file may be the better design.
  • The right answer depends on whether the bytes are buffered, streaming, or persistent.

Course illustration
Course illustration