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

Java WritableByteChannel short writes: drain the ByteBuffer

Last updated: 5 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

WritableByteChannel.write may consume only part of a ByteBuffer, so a complete write requires checking remaining bytes.

Loop on the buffer state

The buffer position advances by the count actually written. Continue until hasRemaining is false. The fixture uses a channel that accepts at most two bytes per call, making the short-write path deterministic instead of relying on a particular filesystem or socket.

FileChannel writing follows the same position rule. For a nonblocking channel, write can return zero because it is not ready; register for writability or apply a deadline instead of spinning forever.

Define completion before publication

Only publish or acknowledge a record once its entire buffer has been accepted by the channel. Acceptance by a channel is not always durable storage: a file may also require a force policy, while a socket needs an application-level acknowledgment if remote processing matters. Atomic file publication handles a separate visibility boundary.

Working program

Java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.StandardCharsets;

public class ManifestChannelWriter {
    static class TwoByteChannel implements WritableByteChannel {
        private final ByteArrayOutputStream sink = new ByteArrayOutputStream();
        private boolean open = true;
        public int write(ByteBuffer source) {
            int count = Math.min(2, source.remaining());
            for (int index = 0; index < count; index++) sink.write(source.get());
            return count;
        }
        public boolean isOpen() { return open; }
        public void close() { open = false; }
        String contents() { return new String(sink.toByteArray(), StandardCharsets.US_ASCII); }
    }

    public static void main(String[] args) throws IOException {
        TwoByteChannel channel = new TwoByteChannel();
        ByteBuffer record = ByteBuffer.wrap("LOT-47".getBytes(StandardCharsets.US_ASCII));
        int calls = 0;
        while (record.hasRemaining()) { channel.write(record); calls++; }
        System.out.println(channel.contents());
        System.out.println("calls=" + calls);
        channel.close();
    }
}

Output

Output
LOT-47
calls=3

Cost and ownership

The loop processes n bytes in O(n) total transfer work and keeps only the input buffer plus the sink. A production nonblocking channel must wait for readiness on zero-byte writes; this blocking-style demonstration always advances and therefore cannot spin.

Common Mistakes

  • Do not assume one write drains the buffer.
  • Do not reset position between partial writes.
  • Do not busy-loop on a nonblocking channel that returns zero.

Read next

Java file channels: buffer positions and partial transfers, Java ByteBuffer flip and compact: preserve an incomplete frame, Java Files.move: atomic publication is a filesystem contract, Java byte streams: partial reads and bounded copying.

java
io
writable-channel-short-write
Storage details