Java NIO

2019-05-21  本文已影响0人  小明今晚加班
NIO和传统IO区别
Java NIO

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

Channel

Channel与Stream差不多是一个等级的,只不过Stream是单向的,比如InputStream、OutputStream.而Channel是双向的,既可以用来读操作,还可以进行写操作。
NIO中Channel的主要实现有:

Buffer(缓冲区)

Buffer类型和Java基本数据类型基本一 一对应,ByteBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer、CharBuffer。除此之外,还有一些应对特种情况(大文件)的Buffer,MappedByteBuffer、HeapByteBuffer、DirectByteBuffer。

Selector

Selector运行单线程可以管理多个channel,如果你的应用打开了多个通道,但每个连接的流量都很低,使用Selector就会很方便。例如在一个聊天服务器中。要使用Selector, 得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新的连接进来、数据接收等。


用FileChannel来举个Buffer+Channel进行IO操作的例子。
首先传统IO代码:

   /**
     * 传统IO举例
     */
    @Test
    public void test2() throws Exception {
        InputStream in = new BufferedInputStream(new FileInputStream("pkg/a.txt"));
        byte[] bytes = new byte[1024];
        int len = in.read(bytes);
        while (len != -1) {
            String str = new String(bytes);
            System.out.println(str);
            len = in.read(bytes);
        }
        in.close();
    }

NIO代码时这样的:

   /**
     * FileChannel举例
     */
    @Test
    public void test1() {
        RandomAccessFile rFile = null;
        try {
            rFile = new RandomAccessFile("pkg/a.txt", "rw");
            FileChannel channel = rFile.getChannel();
            ByteBuffer buf = ByteBuffer.allocate(1024);
            int len = channel.read(buf);
            System.out.println(len);
            while (len != -1) {
                buf.flip();
                System.out.println(StandardCharsets.UTF_8.decode(buf));
                //下面的这种方式容易产生乱码
                // while (buf.hasRemaining()) {
                // System.out.print((char)buf.get());
                // }
                buf.compact();
                len = channel.read(buf);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (rFile != null) {
                    rFile.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }

上面仅仅举例了FileChannel + ByteBuffer的文件读取方式,还有DatagramChannel、SocketChannel、ServerSocketChannel,可以自己根据文档进行熟悉。

这里没有列举Selector的使用,准备后面再另开一篇来写,Selector的内容相对较多一点。

上一篇下一篇

猜你喜欢

热点阅读