Understanding Java IO: From BIO to NIO, Buffers, Channels, and Selectors
This article provides a comprehensive overview of Java IO, explaining the traditional blocking BIO model, the modern non‑blocking NIO architecture, the role of streams, buffers, channels, zero‑copy techniques, and selectors, and includes practical code examples for file copying and simple client‑server communication.
Java IO is a large ecosystem that can be confusing for beginners; this article walks through the fundamentals, starting with the classic blocking I/O (BIO) model and its various input and output streams, buffered streams, and conversion streams.
It then introduces the three main types of streams—byte streams, character streams, and their conversion streams—detailing core classes such as InputStream , OutputStream , Reader , Writer , and their important methods.
The limitations of BIO lead to the newer NIO (New IO) model, which is buffer‑oriented and supports non‑blocking operations. Buffers like ByteBuffer , CharBuffer , and others store data with properties capacity , limit , and position . Example allocation: ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
Channels provide a bidirectional data conduit; common channel classes include FileChannel , SocketChannel , ServerSocketChannel , and DatagramChannel . A typical file‑copy using NIO looks like: FileChannel inChannel = new FileInputStream("src.jpg").getChannel(); FileChannel outChannel = new FileOutputStream("dest.jpg").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); while (inChannel.read(buffer) != -1) { buffer.flip(); outChannel.write(buffer); buffer.clear(); } inChannel.close(); outChannel.close();
Zero‑copy techniques reduce CPU overhead by sharing the same physical memory between user space and kernel space, eliminating unnecessary data copies during file transfer.
Selectors enable a single thread to monitor multiple channels for readiness events (read, write, accept, connect) using SelectionKey . The server example registers a ServerSocketChannel for accept events and client channels for read events: Selector serverSelector = Selector.open(); ServerSocketChannel listener = ServerSocketChannel.open(); listener.bind(new InetSocketAddress(3333)); listener.configureBlocking(false); listener.register(serverSelector, SelectionKey.OP_ACCEPT); while (true) { if (serverSelector.select(1) > 0) { Set keys = serverSelector.selectedKeys(); Iterator it = keys.iterator(); while (it.hasNext()) { SelectionKey key = it.next(); if (key.isAcceptable()) { SocketChannel client = ((ServerSocketChannel) key.channel()).accept(); client.configureBlocking(false); client.register(serverSelector, SelectionKey.OP_READ); } else if (key.isReadable()) { SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buf = ByteBuffer.allocate(1024); client.read(buf); buf.flip(); System.out.println(Charset.defaultCharset().decode(buf).toString()); } it.remove(); } } }
Overall, the article covers the transition from BIO to NIO, the essential classes and methods, performance benefits of buffers, channels, zero‑copy, and selectors, and provides concise code snippets to illustrate each concept.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.