Java NIO

作者: 饱饱想要灵感 | 来源:发表于2023-04-22 21:17 被阅读0次

    一、NIO概念

    Java NIO(New IO)是Java 1.4引入的一组新的IO API,它提供了一种非阻塞的、基于缓冲区的IO操作方式,相比于传统的Java IO(也称为IO流)更加高效和灵活。

    Java NIO的核心组件包括:

    1. 缓冲区(Buffer):用于存储数据的容器,可以读写数据。
    2. 通道(Channel):用于数据的读写,可以从通道中读取数据,也可以将数据写入通道。
    3. 选择器(Selector):用于多路复用IO操作,可以同时监控多个通道的IO事件。

    Java NIO的主要优点包括:

    1. 非阻塞IO:可以在等待IO操作完成的同时执行其他任务,提高了系统的并发性能。
    2. 基于缓冲区的IO:可以减少IO操作的次数,提高了IO操作的效率。
    3. 多路复用IO:可以同时监控多个通道的IO事件,提高了系统的吞吐量。

    二、文件NIO

    下面是一个简单的Java NIO示例,演示了如何使用Java NIO进行文件复制操作:

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class FileCopyExample {
        public static void main(String[] args) throws Exception {
            FileInputStream inputStream = new FileInputStream("source.txt");
            FileOutputStream outputStream = new FileOutputStream("target.txt");
    
            FileChannel inputChannel = inputStream.getChannel();
            FileChannel outputChannel = outputStream.getChannel();
    
            ByteBuffer buffer = ByteBuffer.allocate(1024);
    
            while (inputChannel.read(buffer) != -1) {
                buffer.flip();
                outputChannel.write(buffer);
                buffer.clear();
            }
    
            inputChannel.close();
            outputChannel.close();
            inputStream.close();
            outputStream.close();
        }
    }
    

    在这个示例中,我们使用了Java NIO的FileChannel和ByteBuffer来进行文件复制操作。首先,我们创建了一个FileInputStream和一个FileOutputStream,然后通过它们获取了对应的FileChannel。接着,我们创建了一个ByteBuffer来存储读取到的数据,然后通过循环不断从输入通道中读取数据,将数据写入输出通道中。最后,我们关闭了所有的通道和流。

    需要注意的是,Java NIO的API相对于传统的Java IO来说更加复杂,需要更多的学习和理解。但是,如果能够熟练掌握Java NIO,可以大大提高系统的性能和并发能力。Java NIO(New IO)是Java 1.4引入的一组新的IO API,它提供了一种非阻塞的、基于缓冲区的IO操作方式,相比于传统的Java IO(也称为IO流)更加高效和灵活。

    三、网络NIO

    nio的selector是Java NIO中的一个重要组件,用于监控多个通道的状态,以便在通道就绪时进行处理。使用nio的selector可以实现非阻塞IO,提高系统的并发处理能力。

    selector主要用于网络IO,虽然可以用于文件IO,但不是最优的选择。对于文件IO,更适合使用传统的阻塞IO或者NIO中的FileChannel,例子如第二点。

    使用nio的selector需要以下步骤:

    1. 创建一个Selector对象
    Selector selector = Selector.open();
    
    1. 将通道注册到Selector中
    channel.register(selector, SelectionKey.OP_READ);
    

    其中,第二个参数是一个标志位,表示对应的通道所关心的事件类型,可以是以下四种:

    • SelectionKey.OP_READ:读事件就绪
    • SelectionKey.OP_WRITE:写事件就绪
    • SelectionKey.OP_CONNECT:连接事件就绪
    • SelectionKey.OP_ACCEPT:接受连接事件就绪
    1. 调用Selector的select()方法进行阻塞等待
    selector.select();
    

    该方法会一直阻塞,直到至少有一个通道就绪。

    1. 获取就绪的通道集合
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    
    1. 遍历就绪的通道集合,进行处理
    Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
    while (keyIterator.hasNext()) {
        SelectionKey key = keyIterator.next();
        if (key.isReadable()) {
            // 处理读事件
        } else if (key.isWritable()) {
            // 处理写事件
        } else if (key.isConnectable()) {
            // 处理连接事件
        } else if (key.isAcceptable()) {
            // 处理接受连接事件
        }
        keyIterator.remove();
    }
    
    1. 关闭Selector
    selector.close();
    

    以上就是使用nio的selector的基本步骤。需要注意的是,在处理完一个通道后,需要将其从就绪的通道集合中移除,否则会重复处理。

    以下是一个简单的Socket服务端和客户端示例,使用Selector进行非阻塞IO操作。

    服务端代码:

    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;
    
    public class Server {
        private static final int BUFFER_SIZE = 1024;
        private static final int PORT = 8080;
    
        public static void main(String[] args) throws IOException {
            Selector selector = Selector.open();
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(PORT));
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    
            while (true) {
                selector.select();
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
    
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        SocketChannel socketChannel = server.accept();
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        System.out.println("Accepted connection from " + socketChannel);
                    } else if (key.isReadable()) {
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
                        int bytesRead = socketChannel.read(buffer);
                        if (bytesRead == -1) {
                            socketChannel.close();
                            System.out.println("Connection closed by client: " + socketChannel);
                        } else {
                            buffer.flip();
                            byte[] bytes = new byte[buffer.remaining()];
                            buffer.get(bytes);
                            String message = new String(bytes);
                            System.out.println("Received message from " + socketChannel + ": " + message);
                        }
                    }
                }
            }
        }
    }
    

    客户端代码:

    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.SocketChannel;
    import java.util.Scanner;
    
    public class Client {
        private static final int BUFFER_SIZE = 1024;
        private static final String HOST = "localhost";
        private static final int PORT = 8080;
    
        public static void main(String[] args) throws IOException {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress(HOST, PORT));
    
            while (!socketChannel.finishConnect()) {
                // Wait for connection to be established
            }
    
            System.out.println("Connected to server: " + socketChannel);
    
            Scanner scanner = new Scanner(System.in);
            while (true) {
                String message = scanner.nextLine();
                if (message.equals("exit")) {
                    break;
                }
    
                ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
                socketChannel.write(buffer);
    
                buffer.clear();
                int bytesRead = socketChannel.read(buffer);
                if (bytesRead == -1) {
                    socketChannel.close();
                    System.out.println("Connection closed by server: " + socketChannel);
                    break;
                } else {
                    buffer.flip();
                    byte[] bytes = new byte[buffer.remaining()];
                    buffer.get(bytes);
                    String response = new String(bytes);
                    System.out.println("Received response from server: " + response);
                }
            }
    
            socketChannel.close();
        }
    }
    

    在这个示例中,服务端监听8080端口,客户端连接到该端口并发送消息。服务端接收到消息后,将其打印到控制台上。客户端也会接收到来自服务端的响应,并将其打印到控制台上。

    相关文章

      网友评论

          本文标题:Java NIO

          本文链接:https://www.haomeiwen.com/subject/zvcejdtx.html