Java NIO (New I/O)
Introduction
Java NIO (New I/O), introduced in Java 1.4, provides a high-performance alternative to standard Java IO API. Standard IO (from java.io) is stream-oriented and blocking, which means it reads data sequentially and blocks the executing thread until data is fully read or written.
In contrast, Java NIO is block-oriented (or buffer-oriented) and supports non-blocking operations. It is designed to handle intensive input/output operations efficiently, especially in networked applications (like web servers) where a single server must handle thousands of concurrent connections.
Core Components of Java NIO
The NIO API revolves around three fundamental components:
- Buffers
- Channels
- Selectors
1. Buffers
In standard IO, you read or write data directly from/to streams. In NIO, all data is handled through Buffers. A buffer is essentially a block of memory (an array) that is wrapped in an NIO object providing methods to simplify manipulating that memory.
The most commonly used buffer is ByteBuffer, but others exist like CharBuffer, IntBuffer, LongBuffer, etc.
Key Buffer Properties:
- Capacity: The maximum amount of data the buffer can hold.
- Position: The index of the next element to be read or written.
- Limit: The index of the first element that should not be read or written.
Buffer Usage Pattern:
- Write data into the buffer.
- Call
buffer.flip()to switch from writing mode to reading mode (setslimittoposition, andpositionto 0). - Read data out of the buffer.
- Call
buffer.clear()(to clear the whole buffer) orbuffer.compact()(to clear only read data).
2. Channels
A Channel represents an open connection to an entity such as a hardware device, a file, a network socket, or a software component capable of performing I/O operations.
Unlike streams (which are one-way: InputStream or OutputStream), channels are bi-directional. You can read from a channel into a buffer, and write from a buffer into a channel.
Common Channel Implementations:
FileChannel: Reads data from and to files.DatagramChannel: Reads/writes data over the network via UDP.SocketChannel: Reads/writes data over the network via TCP.ServerSocketChannel: Listens for incoming TCP connections (like a standard web server).
3. Selectors
The Selector is the component that enables Java NIO to be non-blocking and multiplexed. A single thread can use a Selector to monitor multiple Channels for events (e.g., "connection opened", "data arrived", "ready to write").
This means a single thread can manage thousands of active connections without needing to spawn a thread per connection, drastically reducing memory overhead and thread context-switching CPU costs.
Code Example: Reading a File using NIO
Here is a basic example of reading a file using a FileChannel and a ByteBuffer:
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NioFileExample {
public static void main(String[] args) throws Exception {
RandomAccessFile aFile = new RandomAccessFile("data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
// Create buffer with capacity of 48 bytes
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf); // Read into buffer
while (bytesRead != -1) {
System.out.println("Read " + bytesRead);
buf.flip(); // Make buffer ready for read
while(buf.hasRemaining()){
System.out.print((char) buf.get()); // Read 1 byte at a time
}
buf.clear(); // Make buffer ready for writing
bytesRead = inChannel.read(buf);
}
aFile.close();
}
}
NIO vs NIO.2
Java 7 introduced NIO.2 (the java.nio.file package), which provided a much more comprehensive API for file system operations, including the Path interface, the Files utility class, and Asynchronous I/O channels (AsynchronousFileChannel).
// NIO.2 Example for reading all lines of a file
Path path = Paths.get("data.txt");
List<String> lines = Files.readAllLines(path);
When to use NIO?
- Use NIO when you are building high-performance networking applications (chat servers, HTTP servers, gaming servers) that require managing thousands of concurrent connections with a small number of threads.
- Use Standard IO (or NIO.2
FilesAPI) when you are writing basic file manipulation tools, scripts, or applications where you process streams sequentially and thread starvation is not a concern.