Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java byte streams: partial reads and bounded copying

Last updated: 29 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

InputStream reads bytes rather than characters, and a read into a buffer can return fewer bytes than the buffer’s capacity before reaching end of input.

Java 8+. The program uses only JDK classes and runs without a framework.

Copy only the bytes that were read

A parcel scanner uploads a binary manifest. The transfer loop must write the count returned by read, not the entire buffer. Writing the whole buffer after a short final read appends stale bytes from an earlier iteration and corrupts the payload.

The program uses an in-memory input so the byte sequence is reproducible. A three-byte buffer processes a seven-byte payload in several chunks. The final chunk is shorter than the buffer; the copied bytes still match the source exactly. A real file or network stream follows the same count-based contract, although its timing and failure behaviour differ.

An explicit byte limit bounds accepted payload size. The sample checks the remaining budget before writing each chunk. That rejects oversize input but does not erase bytes already emitted to an external destination. Write to a temporary staging destination if publishing must happen only after the entire payload is accepted.

Bytes do not carry a text policy

Wrapping a byte stream in a Reader chooses a character decoder. UTF-8 is a deliberate choice, not an intrinsic property of every input stream. The encoding lesson explains strict rejection of malformed sequences.

available() does not tell you the total file size and is not an end-of-stream test. Use read returning -1 for completion. The caller must also decide who closes the streams. This example creates both streams in main; a library copy method that receives a caller-owned destination should normally leave that destination open.

Working program

Java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
public class BoundedManifestCopy {
    static long copy(InputStream input, OutputStream output, long limit) throws IOException {
        if (limit < 0) throw new IllegalArgumentException("Negative limit");
        byte[] buffer = new byte[3];
        long copied = 0;
        int count;
        while ((count = input.read(buffer)) != -1) {
            if (count > limit - copied) throw new IOException("Payload too large");
            output.write(buffer, 0, count);
            copied += count;
        }
        return copied;
    }
    public static void main(String[] args) throws IOException {
        byte[] manifest = {4, 8, 15, 16, 23, 42, 50};
        try (ByteArrayInputStream input = new ByteArrayInputStream(manifest);
             ByteArrayOutputStream output = new ByteArrayOutputStream()) {
            System.out.println("copied=" + copy(input, output, 10));
            System.out.println(Arrays.toString(output.toByteArray()));
        }
    }
}

Output

Output
copied=7
[4, 8, 15, 16, 23, 42, 50]

Cost and failure boundaries

For B bytes, copying is O(B) work. The loop buffer uses O(c) space for buffer size c; ByteArrayOutputStream in this demonstration also retains O(B) destination storage. Replacing it with a file stream avoids retaining the whole destination in Java heap, but introduces file-system and publication failure policies.

The budget expression compares count with limit minus copied, avoiding overflow from blindly adding before checking. Tests should include empty input, exact-limit input, a one-byte oversize input and a source that throws after returning some bytes. A successful partial write must not be reported as a completed manifest.

Common Mistakes

  • Do not write buffer.length bytes after a short read.
  • Do not use available() as a total-size or completion test.
  • Do not promise rollback for a destination already partially written.

Connect the contracts

Compare the boundary explained in File paths and ownership with the assumptions made by this program.

java
byte-streams
Storage details