NIO流

NIO流

  1. NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区),
    Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

      NIO和传统IO(一下简称IO)之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
    
    IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。
    

    NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。
    非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
    线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
    NIO的实现方式比叫复杂

### Java NIO 的使用教程及示例 Java NIO 是一种高效的输入/输出模型,它通过通道(Channel)、缓冲区(Buffer)以及选择器(Selector)来实现高性能的数据读写操作。以下是关于 Java NIO 的详细介绍及其实际应用。 #### 1. 基本概念 Java NIO 提供了一种全新的方式来进行文件和网络数据的操作。其核心组件包括: - **Channel**: 数据传输的核心接口,类似于传统 IO 中的 Stream。常见的 Channel 实现有 `FileChannel` 和 `SocketChannel` 等[^1]。 - **Buffer**: 数据容器,在 NIO 中所有的数据都必须先放入 Buffer 中才能被 Channel 处理。常用的 Buffer 类型有 `ByteBuffer`, `CharBuffer`, `IntBuffer` 等。 - **Selector**: 负责监控多个 Channel 上的事件(如连接打开、数据到达等),并提供多路复用的功能[^3]。 这些组件共同构成了 Java NIO 的基础架构。 #### 2. 文件读写的简单示例 下面是一个简单的例子,展示如何利用 FileChannel 进行文件的读取与写入操作。 ```java import java.nio.file.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FileReadWriteExample { public static void main(String[] args) throws Exception { Path path = Paths.get("example.txt"); try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)) { ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead = channel.read(buffer); // 将数据从 Channel 读到 Buffer while (bytesRead != -1) { // 当没有更多数据可读时返回 -1 buffer.flip(); // 切换为读模式 while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); // 输出字符 } buffer.clear(); // 清空 Buffer 准备下一次读取 bytesRead = channel.read(buffer); } } // 写入文件的例子 String content = "This is a test."; ByteBuffer writeBuffer = ByteBuffer.wrap(content.getBytes()); try (FileChannel outChannel = FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { outChannel.write(writeBuffer); // 将 Buffer 写入 Channel } } } ``` 上述代码展示了如何使用 `FileChannel` 来完成文件的内容读取和写入过程。 #### 3. 非阻塞服务器端编程实例 另一个重要的场景是非阻塞式的网络通信。这里给出一个基于 Selector 的非阻塞 TCP Server 示例。 ```java import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; public class NonBlockingServer { private final int port; public NonBlockingServer(int port) { this.port = port; } public void start() throws IOException { Selector selector = Selector.open(); ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(false); InetSocketAddress address = new InetSocketAddress(port); serverChannel.socket().bind(address); serverChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Listening on port " + port); while (true) { selector.select(); Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { handleAccept(key, selector); } else if (key.isReadable()) { handleMessage(key); } keyIterator.remove(); } } } private void handleAccept(SelectionKey key, Selector selector) throws IOException { SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept(); clientChannel.configureBlocking(false); clientChannel.register(selector, SelectionKey.OP_READ); System.out.println("Client connected."); } private void handleMessage(SelectionKey key) throws IOException { SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); int numRead = -1; try { numRead = socketChannel.read(readBuffer); } catch (IOException e) { System.err.println("Error reading from client: " + e.getMessage()); key.cancel(); return; } if (numRead == -1) { closeConnection(socketChannel, key); } else { processMessageAndRespond(socketChannel, readBuffer); } } private void closeConnection(SocketChannel socketChannel, SelectionKey key) throws IOException { System.out.println("Closing connection with client..."); key.cancel(); socketChannel.close(); } private void processMessageAndRespond(SocketChannel socketChannel, ByteBuffer buffer) throws IOException { buffer.flip(); CharBuffer charBuffer = Charset.defaultCharset().decode(buffer); System.out.println("Received message: " + charBuffer.toString()); String response = "Echo: " + charBuffer.toString(); byte[] responseBytes = response.getBytes(Charset.defaultCharset()); ByteBuffer outputBuffer = ByteBuffer.wrap(responseBytes); socketChannel.write(outputBuffer); buffer.compact(); } public static void main(String[] args) throws IOException { new NonBlockingServer(8080).start(); } } ``` 这段程序创建了一个能够同时处理多个客户端请求的服务端应用程序。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值