Java I/O Read and Write Methods
Fast recall
Quick revision
Core answer
read and write methods. Reads return the actual number transferred—or -1 at end of input for a non-empty request—so loops must use that count; writes must send only the valid portion of the buffer.Interview-ready guide
Interview answer
Java stream reads come in single-value and bulk forms. InputStream.read() returns an int so it can represent byte values from 0 to 255 and still use -1 for end of input. read(byte[]) and read(byte[], offset, length) return the number of bytes actually placed in the array, which may be smaller than requested.
OutputStream.write(int) writes the low eight bits of the value. Its array overloads write a whole array or a selected range. After a bulk read, the safe pattern is out.write(buffer, 0, count). Writing the whole buffer can copy old bytes left from the previous read.
For example, a six-byte source read through a four-byte buffer may return 4, then 2, then -1. The program writes four bytes after the first read and only two after the second. It must not assume that one read fills the buffer, especially for a socket or another source that may return partial data. Reader and Writer use the same basic pattern with char[].
Convenience methods such as readNBytes, readAllBytes, and transferTo avoid common loop mistakes, but their memory and blocking behavior still matters. readAllBytes is suitable only for bounded input. The central rule is to check -1, respect the returned count, and keep reading until the required amount or end condition is reached.
Java I/O Read and Write Methods
Direct Answer
Java I/O offers single-unit, array, and array-slice read and write methods. Reads return the actual number transferred—or -1 at end of input for a non-empty request—so loops must use that count; writes must send only the valid portion of the buffer.
Deep Dive & Architecture
Stream boundaries do not preserve application message boundaries. One socket read can return half a header, a header plus part of a body, or several small messages, depending on buffering and timing. The application protocol must define framing through a length, delimiter, end-of-stream, or another rule.
Even file reads should use the returned count because the abstract InputStream contract allows partial results. Code that happens to work with one FileInputStream can fail when reused with a socket, decompressor, rate-limited wrapper, or test stream.
available() is not a total-size method. It estimates data that can be read without blocking and can legally return zero while more data will arrive later.
Code Example
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
class ReadWriteMethods {
public static void main(String[] args) throws Exception {
byte[] source = "abcdef".getBytes(StandardCharsets.UTF_8);
try (var in = new ByteArrayInputStream(source);
var out = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4];
int count;
while ((count = in.read(buffer, 0, buffer.length)) != -1) {
out.write(buffer, 0, count);
}
System.out.println(out.toString(StandardCharsets.UTF_8));
}
}
}
Check your understanding
Answer these without looking back at the article.
- Why does InputStream.read return int instead of byte?
- Can a read return fewer bytes than requested before end of stream?
- Why is InputStream.available not the full content length?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.