In-Memory Streams in Java
In-memory streams are streams whose source or destination is memory, such as a byte array or a string, instead of a file. They are used to test code that expects a stream without creating real files, to collect output into a string or byte array, and to pass data in memory to an API that only accepts streams. The main classes are ByteArrayInputStream and ByteArrayOutputStream for bytes, and StringReader and StringWriter (plus CharArrayReader and CharArrayWriter) for characters. In this lesson, you will learn how to use them.
The Classes
| Class | Description |
|---|---|
ByteArrayInputStream(byte[] buf) | It is used to read bytes from an array. |
ByteArrayOutputStream() | It collects written bytes in a growing array; get them with toByteArray() or toString(charset). |
StringReader(String s) | It reads characters from a string. |
StringWriter() | It collects written characters; get them with toString(). |
CharArrayReader(char[] buf) | It reads characters from a char[]. |
CharArrayWriter() | It collects characters; get them with toCharArray() or toString(). |
None of these need closing to release resources, because they don't hold files or sockets; closing them is harmless.
Example: Collecting Output in Memory
Let's see an example that writes a report into a StringWriter and bytes into a ByteArrayOutputStream.
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
public class Collect {
public static void main(String[] args) throws IOException {
StringWriter text = new StringWriter();
try (PrintWriter out = new PrintWriter(text)) {
out.printf("Navika: %d%n", 91);
out.printf("Srihitha: %d%n", 78);
}
System.out.print(text);
System.out.println(text.toString().length() + " characters");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (DataOutputStream data = new DataOutputStream(bytes)) {
data.writeInt(258);
}
System.out.println(Arrays.toString(bytes.toByteArray()));
}
}Navika: 91
Srihitha: 78
24 characters
[0, 0, 1, 2]Explanation: The PrintWriter writes into a StringWriter instead of a file, so the whole report ends up in a string. The DataOutputStream writes into a ByteArrayOutputStream; the int 258 becomes the four bytes 0, 0, 1, 2 (258 = 1 x 256 + 2).
Example: Testing a Method with In-Memory Input
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
public class CountLines {
static int countNonBlank(Reader source) throws IOException {
try (BufferedReader r = new BufferedReader(source)) {
return (int) r.lines().filter(l -> !l.isBlank()).count();
}
}
public static void main(String[] args) throws IOException {
String sample = """
Navika
Srihitha
Advitha
""";
System.out.println(countNonBlank(new StringReader(sample)));
}
}3Explanation: countNonBlank accepts any Reader. In real use it might get a FileReader, but a StringReader lets you test it with a text block, without creating any file.
Common Mistakes
Calling toString() on a ByteArrayOutputStream holding non-ASCII text without a charset. Use toString(StandardCharsets.UTF_8).
Expecting StringWriter to be thread-safe for heavy use. It uses a StringBuffer internally, but building text in one thread with StringBuilder is usually simpler.
Practice
- Easy: Use a
ByteArrayInputStreamover the bytes of "Advitha" and print each byte as a number. - Harder: Write a method
void writeCsv(List<String[]> rows, Writer out), and test it by writing into aStringWriterand checking the result.
Key Takeaways
Was this tutorial helpful?