Java NIO(New I/O)是一種可伸縮且非阻塞的 I/O,與傳統的 Java IO 不同。它允許同時處理多個連接,并且能夠更快地處理 I/O 操作,是構建高性能、可伸縮和并發應用程序的重要組成部分。
(資料圖片)
Java NIO 的核心是 Channel、Buffer 和 Selector。Channel 是連接源和目標的通道,Buffer 是數據傳輸的緩沖區,Selector 用于監視 Channel 中的事件并選擇可用的 Channel 進行操作。下面我們來看一下 Java NIO 的示例。
Channel
在 Java NIO 中,所有的 I/O 操作都是通過 Channel 來進行的。Channel 類似于傳統的流,但又有所不同。在 Channel 中,數據可以從 Channel 中讀取到 Buffer 中,也可以將數據從 Buffer 寫入 Channel 中。
下面是一個從文件中讀取數據并輸出到控制臺的示例:
javaCopy codeimport java.io.*;import java.nio.*;import java.nio.channels.*;public class ChannelExample { public static void main(String[] args) throws IOException { RandomAccessFile file = new RandomAccessFile("test.txt", "rw"); FileChannel channel = file.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); while (channel.read(buffer) != -1) { buffer.flip(); while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } buffer.clear(); } channel.close(); file.close(); }}
在上述示例中,我們使用 FileChannel 打開一個文件,并使用 ByteBuffer 分配一個緩沖區。然后使用 channel.read() 方法從文件中讀取數據到緩沖區,使用 buffer.flip() 方法將緩沖區的指針移到緩沖區的起始位置,并使用 buffer.hasRemaining() 和 buffer.get() 方法遍歷緩沖區中的數據。
Buffer
Buffer 是一個用于讀寫數據的緩沖區,它可以存儲任何類型的數據,例如字節、字符、整數等等。Buffer 是一個抽象類,主要有以下幾種子類:ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer 和 DoubleBuffer。
下面是一個使用 ByteBuffer 存儲數據并將其輸出到控制臺的示例:
import java.nio.*;public class BufferExample { public static void main(String[] args) { ByteBuffer buffer = ByteBuffer.allocate(1024); buffer.put("Hello, world!".getBytes()); buffer.flip(); while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } buffer.clear(); }}
在上述示例中,我們使用 ByteBuffer 分配一個緩沖區,并使用 put() 方法將一個字符串存儲到緩沖區中。然后使用 flip() 方法將緩沖區的指針移到緩沖區的起始位置,并使用 hasRemaining() 和 get() 方法遍歷緩沖區中的數據。
Selector
Selector 用于監視 Channel 中的事件并選擇可用的 Channel 進行操作。在 Java NIO 中,一個線程可以同時處理多個連接,因此它比傳統的 Java IO 更快和更可伸縮。
下面是一個使用 Selector 監視 Channel 的示例:
javaCopy codeimport java.io.*;import java.nio.*;import java.nio.channels.*;public class SelectorExample { public static void main(String[] args) throws IOException { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress("localhost", 8080)); serverSocketChannel.configureBlocking(false); Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { int readyChannels = selector.select(); if (readyChannels == 0) { continue; } for (SelectionKey key : selector.selectedKeys()) { if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel client = server.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); client.read(buffer); buffer.flip(); while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } } selector.selectedKeys().remove(key); } } }}
在上述示例中,我們使用 ServerSocketChannel 打開一個服務器,并使用 Selector 監視該服務器。當有客戶端連接時,使用 accept() 方法獲取客戶端的 SocketChannel 并注冊到 Selector 中,并指定監聽 OP_READ 事件。當客戶端向服務器發送數據時,使用 read() 方法將數據讀取到 ByteBuffer 中,并使用 buffer.hasRemaining() 和 buffer.get() 方法遍歷 ByteBuffer 中的數據。