Skip to main content
The java.nio package provides the New I/O (NIO) APIs introduced in Java 1.4, offering scalable, high-performance I/O operations. The package includes buffers for efficient data handling, channels for I/O operations, and selectors for multiplexed, non-blocking I/O.

Core Concepts

NIO is built around three core abstractions:
  1. Buffers - Containers for data of specific primitive types
  2. Channels - Connections to I/O devices (files, sockets, etc.)
  3. Selectors - Multiplexing of non-blocking channels

Buffer Classes

Buffer

The abstract Buffer class is the foundation for all buffer types. A buffer is a linear, finite sequence of elements of a specific primitive type.
public abstract class Buffer
A buffer has four essential properties:
  • Capacity - The number of elements it contains (never changes)
  • Limit - The index of the first element that should not be read or written
  • Position - The index of the next element to be read or written
  • Mark - The index to which position will be reset when reset() is called
Invariant: 0 <= mark <= position <= limit <= capacity
ByteBuffer buffer = ByteBuffer.allocate(1024);

// Writing data
buffer.put((byte) 42);
buffer.put("Hello".getBytes());

// Prepare for reading
buffer.flip();  // Sets limit to position, position to 0

// Reading data
byte b = buffer.get();
byte[] bytes = new byte[5];
buffer.get(bytes);

// Clear for reuse
buffer.clear();  // Sets position to 0, limit to capacity
Buffer Methods
operations
  • clear() - Prepares buffer for writing (position=0, limit=capacity)
  • flip() - Prepares buffer for reading (limit=position, position=0)
  • rewind() - Prepares for re-reading (position=0, limit unchanged)
  • compact() - Prepares for writing after partial read
  • mark() - Sets mark at current position
  • reset() - Resets position to previously marked position

ByteBuffer

The most commonly used buffer type, providing byte-level access with views for other primitive types.
public abstract class ByteBuffer extends Buffer implements Comparable<ByteBuffer>
// Heap buffer - allocated in JVM heap
ByteBuffer heapBuffer = ByteBuffer.allocate(1024);

// Direct buffer - allocated outside heap (native memory)
ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);

// Direct buffers are more efficient for I/O operations
// but more expensive to allocate/deallocate
System.out.println("Is direct? " + directBuffer.isDirect());

Other Buffer Types

NIO provides specialized buffer classes for each primitive type:
  • CharBuffer - Character data
  • ShortBuffer - 16-bit integers
  • IntBuffer - 32-bit integers
  • LongBuffer - 64-bit integers
  • FloatBuffer - 32-bit floating point
  • DoubleBuffer - 64-bit floating point
// CharBuffer for text processing
CharBuffer charBuffer = CharBuffer.allocate(100);
charBuffer.put("Hello, NIO!");
charBuffer.flip();
System.out.println(charBuffer);

// IntBuffer for numeric data
IntBuffer intBuffer = IntBuffer.allocate(10);
for (int i = 0; i < 10; i++) {
    intBuffer.put(i * i);
}

Channel Classes

Channels represent connections to entities capable of I/O operations (files, sockets, etc.). Unlike streams, channels can be non-blocking and work directly with buffers.

FileChannel

A channel for reading, writing, mapping, and manipulating files.
public abstract class FileChannel extends AbstractInterruptibleChannel
    implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
// Reading from file
try (FileChannel channel = FileChannel.open(
        Paths.get("input.txt"), StandardOpenOption.READ)) {
    
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    
    while (channel.read(buffer) > 0) {
        buffer.flip();
        
        // Process buffer content
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        
        buffer.clear();
    }
}

// Writing to file
try (FileChannel channel = FileChannel.open(
        Paths.get("output.txt"),
        StandardOpenOption.CREATE,
        StandardOpenOption.WRITE)) {
    
    ByteBuffer buffer = ByteBuffer.wrap("Hello, FileChannel!".getBytes());
    channel.write(buffer);
}

SocketChannel

A selectable channel for stream-oriented connecting sockets.
public abstract class SocketChannel extends AbstractSelectableChannel
    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel
// Connect to server (blocking)
SocketChannel channel = SocketChannel.open();
channel.connect(new InetSocketAddress("example.com", 8080));

// Write data
ByteBuffer buffer = ByteBuffer.wrap("GET / HTTP/1.1\r\n\r\n".getBytes());
channel.write(buffer);

// Read response
buffer.clear();
int bytesRead = channel.read(buffer);

buffer.flip();
while (buffer.hasRemaining()) {
    System.out.print((char) buffer.get());
}

channel.close();

ServerSocketChannel

A selectable channel for stream-oriented listening sockets.
public abstract class ServerSocketChannel extends AbstractSelectableChannel
    implements NetworkChannel
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));

System.out.println("Server listening on port 8080");

while (true) {
    // Accept client connection (blocking)
    SocketChannel clientChannel = serverChannel.accept();
    
    // Handle client
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    clientChannel.read(buffer);
    
    buffer.flip();
    clientChannel.write(buffer);
    
    clientChannel.close();
}

DatagramChannel

A selectable channel for datagram-oriented sockets (UDP).
// Send UDP packet
DatagramChannel channel = DatagramChannel.open();
ByteBuffer buffer = ByteBuffer.wrap("Hello, UDP!".getBytes());
channel.send(buffer, new InetSocketAddress("example.com", 9876));

// Receive UDP packet
DatagramChannel receiver = DatagramChannel.open();
receiver.bind(new InetSocketAddress(9876));
ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
SocketAddress sender = receiver.receive(receiveBuffer);

Selector

The Selector class enables multiplexed, non-blocking I/O. A single selector can monitor multiple channels for readiness to perform I/O operations.
public abstract class Selector implements Closeable
// Create selector
Selector selector = Selector.open();

// Configure channel and register with selector
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("example.com", 8080));

// Register for CONNECT and READ events
SelectionKey key = channel.register(
    selector,
    SelectionKey.OP_CONNECT | SelectionKey.OP_READ
);

// Event loop
while (true) {
    // Wait for events (blocking)
    int readyChannels = selector.select();
    
    if (readyChannels == 0) continue;
    
    // Process ready channels
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
    
    while (keyIterator.hasNext()) {
        SelectionKey selectedKey = keyIterator.next();
        
        if (selectedKey.isConnectable()) {
            // Handle connection
        } else if (selectedKey.isReadable()) {
            // Handle read
        } else if (selectedKey.isWritable()) {
            // Handle write
        }
        
        keyIterator.remove();
    }
}
Selection Key Operations
constants
  • OP_READ - Channel is ready for reading
  • OP_WRITE - Channel is ready for writing
  • OP_CONNECT - Channel has completed connection
  • OP_ACCEPT - Channel is ready to accept a connection

MappedByteBuffer

A direct byte buffer whose content is a memory-mapped region of a file.
try (FileChannel channel = FileChannel.open(
        Paths.get("data.bin"), StandardOpenOption.READ, StandardOpenOption.WRITE)) {
    
    MappedByteBuffer mappedBuffer = channel.map(
        FileChannel.MapMode.READ_WRITE, 0, 1024
    );
    
    // Efficient random access
    mappedBuffer.putInt(0, 42);
    mappedBuffer.putLong(4, System.currentTimeMillis());
    
    // Force changes to disk
    mappedBuffer.force();
}
NIO’s buffer-channel architecture provides better performance than traditional stream-based I/O for many use cases, especially when dealing with large amounts of data or when multiplexing I/O operations across multiple connections.
  • java.nio.channels - Channel and selector implementations
  • java.nio.charset - Character encoding/decoding
  • java.nio.file - File system access (Java 7+)
  • java.net - Traditional networking APIs

See Also

  • java.net - Traditional networking APIs
  • java.nio.file - File system APIs

Build docs developers (and LLMs) love