InputStream & OutputStream
TL;DR
InputStreamandOutputStreamare the abstract base classes for all Byte-Oriented I/O in Java.- They process data exactly one byte (8 bits) at a time, making them ideal for binary data (images, PDFs, compiled code).
- The most common concrete implementations are
FileInputStreamandFileOutputStream.
Concept
An InputStream is a source of bytes. An OutputStream is a destination for bytes.
Because they read raw bytes, they are completely ignorant of text encoding (like UTF-8). If you try to use a FileInputStream to read a text file containing the emoji ’😊’ (which takes 4 bytes in UTF-8), the read() method will just return four separate random integers, destroying the text meaning unless you manually reassemble and decode them.
Key Methods
int read(): Reads the next byte of data. Returns-1if the end of the stream is reached. (Note: It returns anintbetween 0 and 255, not abyte, so it can use-1as the EOF signal).void write(int b): Writes the specified byte to the output destination.
Examples
import java.io.*;
public class ByteStreamDemo {
public static void copyFile(String source, String dest) {
// Use try-with-resources to ensure streams close automatically
try (InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(dest)) {
// OPTIMIZATION: Do not read 1 byte at a time!
// Create a 4KB buffer in RAM.
byte[] buffer = new byte[4096];
int bytesRead;
// Read up to 4096 bytes at once into the buffer
while ((bytesRead = in.read(buffer)) != -1) {
// Write exactly the number of bytes that were read
out.write(buffer, 0, bytesRead);
}
System.out.println("File copied successfully!");
} catch (IOException e) {
System.err.println("I/O Error: " + e.getMessage());
}
}
}
Interview Questions
Q: Why does InputStream.read() return an int instead of a byte?
A: A Java byte is signed, ranging from -128 to 127. If you are reading a binary file (like a JPEG), it is perfectly normal to read a byte consisting of all 1s (11111111). If parsed as a signed Java byte, that value is -1.
However, the read() method needs a special sentinel value to tell you that it has reached the End of File (EOF). It uses -1 for this. If read() returned a byte, you wouldn’t know if the -1 meant “End of file” or “I just read a white pixel in the JPEG”. By returning a 32-bit int, it maps valid bytes to 0 through 255, reserving the integer -1 exclusively for EOF.
Q: What is the ByteArrayInputStream used for?
A: It is an InputStream that reads bytes from a pre-existing byte[] array already in memory, rather than from a hard drive or network. It is incredibly useful for writing Unit Tests (where you want to mock an InputStream to pass into a method) or for adapting in-memory data to an API that strictly requires an InputStream.