InputStream.read(byte[]) may return fewer bytes than requested even when the stream has not ended.
Java InputStream short reads: assemble a complete record header
Treat the return count as the contract
A read call reports how many bytes it placed into the destination, or -1 at end of stream. A network stream, decompressor, or wrapper can deliver only part of a header. Parse only after the declared header width is present. A short positive read is progress, not proof of truncation.
The loop below reads a four-byte message length from a stream that deliberately releases one byte per call. It rejects EOF before four bytes arrive. Follow the length with a separate payload boundary; a valid header never proves that the body is complete.
Keep parser state local
Do not publish a partially filled header to downstream code. The caller receives a length only after all four bytes are assembled. A real framing protocol should also reject negative lengths and cap allocations before reading its payload; byte-stream copying covers the general read loop.
Working program
import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
public class InventoryFrameHeader {
static int readLength(InputStream source) throws IOException {
byte[] header = new byte[4];
int received = 0;
while (received < header.length) {
int count = source.read(header, received, header.length - received);
if (count == -1) throw new EOFException("short header");
if (count == 0) continue;
received += count;
}
return ((header[0] & 255) << 24) | ((header[1] & 255) << 16)
| ((header[2] & 255) << 8) | (header[3] & 255);
}
public static void main(String[] args) throws IOException {
byte[] wire = {0, 0, 0, 47};
InputStream throttled = new ByteArrayInputStream(wire) {
@Override public synchronized int read(byte[] target, int offset, int length) {
return super.read(target, offset, Math.min(length, 1));
}
};
System.out.println(readLength(throttled));
try { readLength(new ByteArrayInputStream(new byte[] {0, 0, 0})); }
catch (EOFException truncated) { System.out.println(truncated.getMessage()); }
}
}Output
47
short headerCost and ownership
The header uses four bytes of fixed storage and O(4) read work, although a slow source can require four separate calls. A production loop also needs a deadline or cancellation policy for sources that can stall; the byte count alone does not impose one.
Common Mistakes
- Do not assume one read fills the requested array.
- Do not parse a header after a positive but short read.
- Do not allocate a body directly from an unchecked length field.
Read next
readnbytes truncated frame, datainputstream readfully eof, Java byte streams: partial reads and bounded copying, inputstream available not length.
