java NIO

java NIO(New IO Non Blocking IO)是从java1.4版本开始引入的一个新IO API,可以替代标准的java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的,基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。

IONIO
面向流(Stream Oriented)面向缓冲区(Buffer Oriented)
阻塞IO(Blocking IO)非阻塞IO(Non Blocking IO)
选择器(Selector)

IO

在这里插入图片描述

NIO


也就是把数据存在缓冲区上来传输,存获取
NIO核心就是在于通道和缓冲区,使用NIO系统,需要获得连接IO设备的通道,以及用于容纳数据的缓冲区(小车),然后操作缓冲区进行处理。
通道负责传输,缓冲区用于存储
缓冲区一系列方法

package com.rlw.Nio;

import java.nio.ByteBuffer;

/* *
 * @Author ren_li_wei
 * 一。缓冲区Buffer:在java NIo中负责数据的存取,缓冲区就是数组,用于存着不同数据类型的数据
 * 根据数据类型不同,提供了相应的缓冲区(没有boolean)
 * 例如
 * ByteBuffer
 * IntBuffer
 * ...
 * 都是通过allocate()获取缓冲区
 * 二。缓冲区存储数据有两个方法:
 * put,存放
 * get,获取
 * @Date 21:13 2021/4/15
 * @Param
 * @return
 * */

/**
 * // Invariants: mark <= position <= limit <= capacity
 *     private int mark = -1; 标记当前position的位置,可以通过reset()恢复到mark的位置
 *     private int position = 0; 位置,表示缓冲区中正在操作数据的位置
 *     private int limit; 界限表示缓冲区中可以操作数据的大小(limit后面的数据是不能进行读写的)
 *     private int capacity; 容量的意思,表示缓冲区中最大存储数据的容量,一旦声明不可改变
 *
 *     龟绿:0 <= position <= limit <= capacity
 */
public class NioDemo {
    public static void main(String[] args) {
        String str = "abcde";
        //分配指定大小的缓冲区
        ByteBuffer  byteBuffer = ByteBuffer.allocate(1024);
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        //存数据
        byteBuffer.put(str.getBytes());
        System.out.println("============存=================");
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        System.out.println("============切换模式=================");
        //切换读取数据模式
        byteBuffer.flip();
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        //读数据到数组中
        System.out.println("============取=================");
        byte[] res = new byte[byteBuffer.limit()];
        byteBuffer.get(res);
        System.out.println(new String (res,0,res.length));
        System.out.println("============取完之后=================");
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        //rewind,可重复读数据
        byteBuffer.rewind();
        System.out.println("============rewind之后=================");
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        //clear 清空缓冲区,但是里面的数据还在,只不过处于一种被遗忘状态,随时可能会被垃圾回收
        byteBuffer.clear();
        System.out.println("============clear之后=================");
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());

    }
}

0
1024
1024
------------------存=================
5
1024
1024
------------------切换模式=================
0
5
1024
------------------取=================
abcde
------------------取完之后=================
5
5
1024
------------------rewind之后=================
0
5
1024
------------------clear之后=================
0
1024
1024

package com.rlw.Nio;

import java.nio.Buffer;
import java.nio.ByteBuffer;

public class NioDemo2 {
    public static void main(String[] args) {
        String sr = "abcde";
        ByteBuffer buff = ByteBuffer.allocate(1024);
        buff.put(sr.getBytes());
        buff.flip();
        byte[] bytes = new byte[buff.limit()];
        buff.get(bytes,0,2);
        System.out.println(new String(bytes,0,2));
        System.out.println("position位置是"+buff.position());
        //标记
        buff.mark();
        buff.get(bytes,2,2);
        System.out.println(new String (bytes,2,2));
        System.out.println("position位置是"+buff.position());
        //reset,恢复到mark位置
        buff.reset();
        System.out.println("position位置是"+buff.position());
    }
}

ab
position位置是2
cd
position位置是4
position位置是2

在这里插入图片描述
到这里从而可以得到positon-limit之间的数据,也就是读取数据
以上都是非直接缓冲区

直接缓冲区和非直接缓冲区

非直接缓冲区通过方法allocate()方法分配缓冲区,将缓冲区建立于JVM的内存中
直接缓冲区通过alllocateDirect()方法分配直接缓冲区,将缓冲区建立于物理内存中,可以提高效率
在这里插入图片描述

在这里插入图片描述
两个缺点,1,相比非直接缓冲区占用空间;2,当我们使用java程序操作时,不再像以前一样数据写或读在jvm上,而是在物理内存中,我们对其失去了控制权

package com.rlw.Nio;

import java.nio.ByteBuffer;

public class NioDemo3 {
    public static void main(String[] args) {
        /* *
         * @Author ren_li_wei
         * @Description //TODO  操作与非直接缓冲区相同
         * @Date 20:45 2021/4/16
         * @Param [args]
         * @return void
         * */
        String str = "abcde";
        //分配直接缓冲区
        ByteBuffer  byteBuffer = ByteBuffer.allocateDirect(1024);
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        //存数据
        byteBuffer.put(str.getBytes());
        System.out.println("============存=================");
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        System.out.println("============切换模式=================");
        //切换读取数据模式
        byteBuffer.flip();
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        //读数据到数组中
        System.out.println("============取=================");
        byte[] res = new byte[byteBuffer.limit()];
        byteBuffer.get(res);
        System.out.println(new String (res,0,res.length));
        System.out.println("============取完之后=================");
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        //rewind,可重复读数据
        byteBuffer.rewind();
        System.out.println("============rewind之后=================");
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());
        //clear 清空缓冲区,但是里面的数据还在,只不过处于一种被遗忘状态,随时可能会被垃圾回收
        byteBuffer.clear();
        System.out.println("============clear之后=================");
        System.out.println(byteBuffer.position());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.capacity());

    }
}

0
1024
1024
=====
5
1024
1024
切换模式=====
0
5
1024
=====
abcde
取完之后=====
5
5
1024
rewind之后=====
0
5
1024
clear之后=====
0
1024
1024

通道(Channel)

通道(Channel):由java.nio.channels包定义的,channel表示与io源与目标打开的连接
channel类似于传统的流,只不过channel本身不能直接访问数据,channel只能与buffer进行交互
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package com.rlw.Nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * 通道(Channel):用于源节点与目标节点的连接,在java NIO中负责缓冲区数据的传输,
 *                 通道本身不会传输数据,因此需要缓冲区配合,通道是马路,缓冲区是小车
 * 通道的主要实现类
 * java.nio.channels.Channel接口:
 * FileChannel    只有file是面向本地的 其他都是面向网络的
 * SocketChannel
 * ServerSocketChannel
 * DatagramChannel
 *
 * 获取通道
 * 1.java针对支持通道的类提供了getChannel()的方法
 *      本地IO:
 *      FileInputStream/FileOutputStream
 *      RandomAccessFile
 *
 *      网络IO:
 *      Socket
 *      ServerSocket
 *      DataGramSocket
 * 2.在jdk1.7中的NIO.2针对各个通道提供了静态方法open()
 * 3.在jdk1.7中的NIO.2Files工具类的newByteChannel()
 */
public class ChannelDemo {
    //利用通道完成对文件的复制
    public static void main(String[] args) throws IOException {
        FileInputStream is = null;
        FileOutputStream os = null;
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            is = new FileInputStream("1.png");
            os = new FileOutputStream("2.png");
            //获取通道
            inChannel = is.getChannel();
            outChannel = os.getChannel();
            /**
             * 马路铺完之后该到小车了
             */
            //分配指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);

            /**
             * 将马路一边的人接到另一边
             */
            //将通道中的数据读入到缓冲区中
            while(inChannel.read(buf)!=-1){
                buf.flip();//切换到读取模式
                //将缓冲区中的数据写入到通道另一边
                outChannel.write(buf);
                buf.clear();//清空缓冲区 以便下次再往缓冲区中写
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outChannel!=null){
                outChannel.close();
            }
            if (inChannel!=null){
                inChannel.close();
            }
            if (os!=null){
                os.close();
            }
            if (is!=null){
                is.close();
            }
        }
    }
}

在这里插入图片描述
说实话这个管道我觉得与正常的io没啥区别


直接与非直接缓冲区的区别

非直接缓冲区

package com.rlw.Nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * 通道(Channel):用于源节点与目标节点的连接,在java NIO中负责缓冲区数据的传输,
 *                 通道本身不会传输数据,因此需要缓冲区配合,通道是马路,缓冲区是小车
 * 通道的主要实现类
 * java.nio.channels.Channel接口:
 * FileChannel    只有file是面向本地的 其他都是面向网络的
 * SocketChannel
 * ServerSocketChannel
 * DatagramChannel
 *
 * 获取通道
 * 1.java针对支持通道的类提供了getChannel()的方法
 *      本地IO:
 *      FileInputStream/FileOutputStream
 *      RandomAccessFile
 *
 *      网络IO:
 *      Socket
 *      ServerSocket
 *      DataGramSocket
 * 2.在jdk1.7中的NIO.2针对各个通道提供了静态方法open()
 * 3.在jdk1.7中的NIO.2Files工具类的newByteChannel()
 */
public class ChannelDemo {
    //利用通道完成对文件的复制
    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();
        FileInputStream is = null;
        FileOutputStream os = null;
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            is = new FileInputStream("d:/1.tqs");
            os = new FileOutputStream("d:/2.tqs");
            //获取通道
            inChannel = is.getChannel();
            outChannel = os.getChannel();
            /**
             * 马路铺完之后该到小车了
             */
            //分配指定大小的f非直接缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);

            /**
             * 将马路一边的人接到另一边
             */
            //将通道中的数据读入到缓冲区中
            while(inChannel.read(buf)!=-1){
                buf.flip();//切换到读取模式
                //将缓冲区中的数据写入到通道另一边
                outChannel.write(buf);
                buf.clear();//清空缓冲区 以便下次再往缓冲区中写
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outChannel!=null){
                outChannel.close();
            }
            if (inChannel!=null){
                inChannel.close();
            }
            if (os!=null){
                os.close();
            }
            if (is!=null){
                is.close();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }
}

复制了一段视频 运行时间为:423


直接缓冲区

package com.rlw.Nio;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
/**
 * 获取通道
 * * 1.java针对支持通道的类提供了getChannel()的方法
 * *      本地IO:
 * *      FileInputStream/FileOutputStream
 * *      RandomAccessFile
 * *
 * *      网络IO:
 * *      Socket
 * *      ServerSocket
 * *      DataGramSocket
 * * 2.在jdk1.7中的NIO.2针对各个通道提供了静态方法open()
 * * 3.在jdk1.7中的NIO.2Files工具类的newByteChannel()
 */
public class ChannelDemo2 {
    //在jdk1.7中的NIO.2针对各个通道提供了静态方法open()
    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        //获取通道
        FileChannel inChannel = FileChannel.open(Paths.get("d:/1.tqs"), StandardOpenOption.READ);
        //复制 还得来一个
        FileChannel outChannel = FileChannel.open(Paths.get("d:/2.tqs"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //直接缓冲区,ByteBuffer.allocateDirect()等同于下面的写法,都是获取直接缓冲区
        //内存映射文件,不再像非之间那样反复复制,直接缓冲在物理内存中
        MappedByteBuffer inMap = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMap = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
        byte[] bytes = new byte[inMap.limit()];
        inMap.get(bytes);
        outMap.put(bytes);
        inChannel.close();
        outChannel.close();
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }
}

在这里插入图片描述
复制了一段视频 运行时间为:95

到这里才体现出了不同之处,直接缓冲区在文件大的时候会体现出很大的优势


通道之间数据传输(直接缓冲区)

public class ChannelDemo3 {
    //通道之间数据传输,直接缓冲区
    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();
        //获取通道
        FileChannel inChannel = FileChannel.open(Paths.get("d:/1.tqs"), StandardOpenOption.READ);

        //复制 还得来一个
        FileChannel outChannel = FileChannel.open(Paths.get("d:/2.tqs"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
//        inChannel.transferTo(0,inChannel.size(),outChannel);
        outChannel.transferFrom(inChannel,0,inChannel.size());
        outChannel.close();
        inChannel.close();
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }
}

复制视频耗时:61


分散(Scatter)和聚集(Gather)

分散读取(Scatter Reads)是指从Channel中读取数据"分散"到多个Buffer中。
在这里插入图片描述
按照缓冲区的顺序,从Channel中读取的数据依次Buffer填满


聚集写入(Gathering Writes)是指将多个Buffer中的数据"聚集"到Channel。
在这里插入图片描述
按照缓冲区的顺序,写入postionlimit之间的数据到Channel


package com.rlw.Nio;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ChannelDemo4 {
    /**
     *  分散(Scatter)和聚集(Gather)
     *  分散读取(Scattering Reads):将通道中的数据分散到缓冲区中
     *  聚集谢日(Gathering Writes):将多个缓冲区中的数据聚集到通道中
     * @param args
     */
    public static void main(String[] args) throws IOException {

        //分散和聚集
        RandomAccessFile raf = new RandomAccessFile("d:/sql.sql","rw");
        //得到通道
        FileChannel channel = raf.getChannel();
        //分配指定大小缓冲区
        ByteBuffer buf1 =  ByteBuffer.allocate(100);
        ByteBuffer buf2 =  ByteBuffer.allocate(1024);
        /**
         * 分散读取
         * 按顺序读过来
         */
        ByteBuffer[] arr = {buf1,buf2};
        channel.read(arr);
        for (ByteBuffer byteBuffer:arr) {
            byteBuffer.flip();
        }
        System.out.println(new String(arr[0].array(),0,arr[0].limit()));
        System.out.println(new String(arr[1].array(),0,arr[1].limit()));
        /**
         * 聚集写入
         * //按顺序写过来的
         */
        RandomAccessFile raf2 = new RandomAccessFile("d:/sql2.sql","rw");
        //得到通道
        FileChannel channel1 = raf2.getChannel();
        channel1.write(arr);
    }
}

字符集:Charset

编码:字符串->字节数组
解码:字节数组->字符串

package com.rlw.Nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

public class ChannelDemo5 {
    public static void main(String[] args) throws IOException {
//        SortedMap<String, Charset> map = Charset.availableCharsets();
//        //获取所有编码
//        Set<Map.Entry<String, Charset>> entries = map.entrySet();
//        for (Map.Entry<String, Charset> ee:entries) {
//            System.out.println(ee);
//        }
        Charset  cs = Charset.forName("GBK");
        //获取编码器
        CharsetEncoder ce = cs.newEncoder();
        //获取解码器
        CharsetDecoder cd = cs.newDecoder();

        //获取缓冲区
        CharBuffer cBuffer = CharBuffer.allocate(1024);
        cBuffer.put("任立伟最帅");
        cBuffer.flip();//切换状态
        //按照GBK编码
        ByteBuffer buffer = ce.encode(cBuffer);
        for (int i =0;i<10;i++){//一个汉字两个字节,编码是变成数组,所以需要循环
            System.out.println(buffer.get());
        }
        //按照GBK解码
        buffer.flip();
        CharBuffer decode = cd.decode(buffer);
            System.out.println(decode.toString());

        //测试一下按照UTF-8解码
        Charset charset = Charset.forName("UTF-8");
        buffer.flip();
        CharBuffer decode1 = charset.decode(buffer);
      System.out.println(decode1.toString());
    }
}

在这里插入图片描述


阻塞与非阻塞

在这里插入图片描述
在这里插入图片描述
阻塞式IO

package com.rlw.Nio;

import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/* *
 * @Author ren_li_wei
 * @Description //TODO 
 * @Date 21:28 2021/4/17
 * 使用NIO完成网络通信的三个核心
 * 1通道(Channel):负责连接
 * java.nio.channels.Channel接口:
 * SelectableChannel
 *      SocketChannel
 *      ServerSocketChannel
 *      DataGramChannel
 *
 *      Pope.SinkChannel
 *      Pipe.SourceChannel
 * 缓冲区(Buffer):负责数据的存取
 *
 * 选择器:时SelectableChannel的多路复用器,用于监控SelectableChannel的IO状况
 * */

public class BlockingNioDemo {
    //客户端
    @Test
    public void client() throws IOException {
        //1获取通道
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
        //分配指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        //读取本地文件并发送到服务端去
        FileChannel inChannel = FileChannel.open(Paths.get("1.png"), StandardOpenOption.READ);
        while(inChannel.read(buf)!=-1){
            buf.flip();
            sChannel.write(buf);
            buf.clear();
        }
        //关闭通道
        inChannel.close();
        sChannel.close();
    }
    //服务端
    @Test
    public void server() throws IOException{
        //获取通道
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
        //保存客户端的数据需要一个通道
        FileChannel fileChannel = FileChannel.open(Paths.get("2.jpg"),StandardOpenOption.WRITE,StandardOpenOption.CREATE);
        //绑定链接
        ssChannel.bind(new InetSocketAddress(9898));
        //获取客户端连接通道 侦听并接受到此套接字的连接
        SocketChannel sChannel = ssChannel.accept();
        //接收客户端的数据,并保存在本地...需要有缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        while (sChannel.read(buf)!=-1){
            buf.flip();
            fileChannel.write(buf);
            buf.clear();
        }
        sChannel.close();
        fileChannel.close();
        ssChannel.close();
    }
}

阻塞IO反馈信息以及执行流程
在这里插入图片描述
非阻塞式NIO(有了选择器)

package com.rlw.Nio;

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;
import java.util.Scanner;

import org.junit.Test;

/*
 * 一、使用 NIO 完成网络通信的三个核心:
 *
 * 1. 通道(Channel):负责连接
 *
 * 	   java.nio.channels.Channel 接口:
 * 			|--SelectableChannel
 * 				|--SocketChannel
 * 				|--ServerSocketChannel
 * 				|--DatagramChannel
 *
 * 				|--Pipe.SinkChannel
 * 				|--Pipe.SourceChannel
 *
 * 2. 缓冲区(Buffer):负责数据的存取
 *
 * 3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况
 *
 */
public class NoBlockingNIO {

    //客户端
    @Test
    public void client() throws IOException{
        //1. 获取通道
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));

        //2. 切换非阻塞模式
        sChannel.configureBlocking(false);

        //3. 分配指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);

        //4. 发送数据给服务端
        Scanner scan = new Scanner(System.in);

        while(scan.hasNext()){
            String str = scan.next();
            buf.put(str.getBytes());
            buf.flip();
            sChannel.write(buf);
            buf.clear();
        }

        //5. 关闭通道
        sChannel.close();
    }

    //服务端
    @Test
    public void server() throws IOException{
        //1. 获取通道
        ServerSocketChannel ssChannel = ServerSocketChannel.open();

        //2. 切换非阻塞模式
        ssChannel.configureBlocking(false);

        //3. 绑定连接
        ssChannel.bind(new InetSocketAddress(9898));

        //4. 获取选择器
        Selector selector = Selector.open();

        //5. 将通道注册到选择器上, 并且指定“监听接收事件”
        ssChannel.register(selector, SelectionKey.OP_ACCEPT);

        //6. 轮询式的获取选择器上已经“准备就绪”的事件
        while(selector.select() > 0){

            //7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();

            while(it.hasNext()){
                //8. 获取准备“就绪”的是事件
                SelectionKey sk = it.next();

                //9. 判断具体是什么事件准备就绪
                if(sk.isAcceptable()){
                    //10. 若“接收就绪”,获取客户端连接
                    SocketChannel sChannel = ssChannel.accept();

                    //11. 切换非阻塞模式
                    sChannel.configureBlocking(false);

                    //12. 将该通道注册到选择器上
                    sChannel.register(selector, SelectionKey.OP_READ);
                }else if(sk.isReadable()){
                    //13. 获取当前选择器上“读就绪”状态的通道
                    SocketChannel sChannel = (SocketChannel) sk.channel();

                    //14. 读取数据
                    ByteBuffer buf = ByteBuffer.allocate(1024);

                    int len = 0;
                    while((len = sChannel.read(buf)) > 0 ){
                        buf.flip();
                        System.out.println(new String(buf.array(), 0, len));
                        buf.clear();
                    }
                }

                //15. 取消选择键 SelectionKey
                it.remove();
            }
        }
    }
}

在这里插入图片描述
在这里插入图片描述
UDP

package com.atguigu.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Date;
import java.util.Iterator;
import java.util.Scanner;

import org.junit.Test;

public class TestNonBlockingNIO2 {
	
	@Test
	public void send() throws IOException{
		DatagramChannel dc = DatagramChannel.open();
		
		dc.configureBlocking(false);
		
		ByteBuffer buf = ByteBuffer.allocate(1024);
		
		Scanner scan = new Scanner(System.in);
		
		while(scan.hasNext()){
			String str = scan.next();
			buf.put((new Date().toString() + ":\n" + str).getBytes());
			buf.flip();
			dc.send(buf, new InetSocketAddress("127.0.0.1", 9898));
			buf.clear();
		}
		
		dc.close();
	}
	
	@Test
	public void receive() throws IOException{
		DatagramChannel dc = DatagramChannel.open();
		
		dc.configureBlocking(false);
		
		dc.bind(new InetSocketAddress(9898));
		
		Selector selector = Selector.open();
		
		dc.register(selector, SelectionKey.OP_READ);
		
		while(selector.select() > 0){
			Iterator<SelectionKey> it = selector.selectedKeys().iterator();
			
			while(it.hasNext()){
				SelectionKey sk = it.next();
				
				if(sk.isReadable()){
					ByteBuffer buf = ByteBuffer.allocate(1024);
					
					dc.receive(buf);
					buf.flip();
					System.out.println(new String(buf.array(), 0, buf.limit()));
					buf.clear();
				}
			}
			
			it.remove();
		}
	}

}

管道
java NIO 管道是2个线程之间的单项数据连接。PIpe有一个source通道和一个sink通道。数据会被写到sink通道,从source中读取

package com.atguigu.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;

import org.junit.Test;

public class TestPipe {

	@Test
	public void test1() throws IOException{
		//1. 获取管道
		Pipe pipe = Pipe.open();
		
		//2. 将缓冲区中的数据写入管道
		ByteBuffer buf = ByteBuffer.allocate(1024);
		
		Pipe.SinkChannel sinkChannel = pipe.sink();
		buf.put("通过单向管道发送数据".getBytes());
		buf.flip();
		sinkChannel.write(buf);
		
		//3. 读取缓冲区中的数据
		Pipe.SourceChannel sourceChannel = pipe.source();
		buf.flip();
		int len = sourceChannel.read(buf);
		System.out.println(new String(buf.array(), 0, len));
		
		sourceChannel.close();
		sinkChannel.close();
	}
	
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值