Java NIO基础入门

NIO

1. Java NIO的简介

​ NIO官网叫New IO 也可以叫做式非阻塞式IO NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区,基于通道的IO操作,NIO将以更高效的方式进行文件的读写操作

2.Java NIO与IO的主要区别

​ 原来的IO是面对数据流 传统的IO是单向的 阻塞式的IO

​ 而NIO面向缓冲区(通道)(铁路) 通道只负责运输 数据只在缓冲区 非阻塞的IO 拥有选择器

​ NIO简而言之:通道负责传输,,缓冲区负责存储

3.***缓冲区(Buffer)和通道(Channel)

​ 除了Boolean之外 每个基本的数据类型都有缓冲区
​ ByteBuffer常用的

​ 上述缓冲区的管理方式都是一致的 通过allocate()获取缓冲区
​ ByteBuffer bb = ByteBuffer.allocate(1024);

​ 存数据的和取方法
​ put();
​ get();

​ flip():切换读或写方法莫模式flip 换切换以下3个属性的位置!!!

​ rewind():重复读取数据

​ clear清空缓冲区回到了最初的状态 里面的数据还在 只是移动角标位置

缓冲区中的四个核心属性

  1. capacity:容量,表示缓冲区中最大的存储数据的容量,一旦生命就不能改变;
  2. limit:界限,表示缓冲区中可以操作数据的大小(limit 后面的数据是不能进行读写的)
  3. position:位置,表示缓冲区中正在操作的位置。
  4. mark:标记 记录当前pisition的位置 通过reset恢复到mark的位置

非直接缓冲区

​ 通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中

​ 数据没办法直接传输 要从磁盘写道内核地址空间 再写到用户地址空间

直接缓冲区

​ 通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率

​ Zero copy

一个独立的通道不占用CPU处理IO操作

/**
 * 1.通道(channel):用于原节点与目标节点的连接,在javaNIO中负责缓冲区中数据传输
 * channel本身不存储数据 需要配合缓冲区进行传输
 * 2.通道的主要实现类
 * java.nio.channels.channel
 *        ---FileChannel            用于本地传输
 *        ---SocketChaneel          TCP
 *        ---ServerSocketChannel
 *        ---DatagramChannel        UDP
 * 3。Java支持通道提供了getChannel()方法
 *       本地IO
 *      ---FileInputStream/FileOutputStream
 *      ---RandomAccessFile
 *      网络IO
 *      Socket
 *      ServerSocket
 *      DatagramSocket
 *      jdk7中的nio2   在JDK7以后的nio统称NIO2
 *      提供了一个静态方法open()  也可以获取通道
 *      针对Files工具类的newByteChannel()
 * 4.通道之间的数据传输
 * transferFrom();
 * transTo();
 */
public class NIOTest {
     
    

    @Test
    public void test() throws Exception {
     
    //一,利用通道完成文件的复制(非直接缓冲区)
        FileInputStream fis = new FileInputStream("jvm.png");
        FileOutputStream fos = new FileOutputStream("1.png");

        //1.获取通道
        FileChannel inChannel = fis.getChannel();
        FileChannel outChannel = fos.getChannel();

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

        //3.将通道中的数据存入缓冲区中
        while(inChannel.read(buf) != -1){
     
            //4.将缓冲区中的数据再写入通道
            buf.flip();     // 切换成读数据的模式
            outChannel.write(buf);
            buf.clear();  //清空缓冲区
        }
        outChannel.close();
        inChannel.close();
        fos.close();
        fis.close();
    }
    @Test
    public void test2() throws IOException {
     
        //使用直接缓冲区完成复制文件
        FileChannel inChannel = FileChannel.open(Paths.get("1.png"), StandardOpenOption.READ);
        //CREAT_NEW  如果有报错  没有创建
        FileChannel outChannel = FileChannel.open(Paths.get("2.png"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
        //内存映射文件   直接缓冲区只有bytebuffer支持
        MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMapperBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());

        //不需要通道 直接操作缓冲区
        byte[] dst = new byte[inMappedBuf.limit()];
        inMappedBuf.get(dst);
        outMapperBuf.put(dst);
        inChannel.close();
        outChannel.close();
    }
    @Test
    public void test3() throws Exception {
     
        //直接缓冲区的方式
        FileChannel inChannel = FileChannel.open(Paths.get("1.png"), StandardOpenOption.READ);
        //CREAT_NEW  如果有报错  没有创建
        FileChannel outChannel = FileChannel.open(Paths.get("3.png"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);

        long l = inChannel.transferTo(0, inChannel.size(), outChannel);
        inChannel.close();
        outChannel.close();
    }
}

分散与读取

分散读取 将通道的数据分散到多个缓冲区中

聚集写入 将多个缓冲区的数据聚集到一个通道中

4.文件通道(FileChannel)

5.NIO的非阻塞式通信

​ NIO与IO的区别 IO是阻塞式的 如果客户端发送一个读写请求 服务端如果不能够确定发送的东西是否有效 是否有数据就会发生阻塞 判断内核地址空间有没有数据

​ NIO式非阻塞 式相较于网络通信来说的

  1. ***选择器(Selector)

    ​ 就是在文件中间加一个选择器 就是在准备好了的时候才通过选择器建立连接,,而不会因为服务端的不确定而出现了阻塞

    //服务器端
    public static void main(String[] args) throws IOException {
           
            //1.获取通道
            ServerSocketChannel ssChannel = ServerSocketChannel.open();
            //2.切换非阻塞模式
            ssChannel.configureBlocking(false);
            //3.绑定连接
            ssChannel.bind(new InetSocketAddress(10086));
            //4.获取选择器
            Selector selector = Selector.open();
            //5.将通道注册到选择器上   后面的参数是选择键  监控状态的什么时间/状态  读写接收
            //ACCEPT接收  指定监听事件
            ssChannel.register(selector, SelectionKey.OP_ACCEPT);
            //6.轮询式的获取选择器上已经准备就绪的事件
            while (selector.select() > 0) {
           
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                //7.获取当前选择器中所有注册的选择键(已就绪的监听事件)
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while(iterator.hasNext()){
           
                    //8.获取准备就绪的事件
                    SelectionKey sk = iterator.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.取消选择键 SelectorKey
                    iterator.remove();
                }
            }
        }
    //客户端
    public static void main(String[] args) throws IOException {
           
            //1.获取通道
            SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 10086));
    
            //2.切换成非阻塞模式
            sChannel.configureBlocking(false);
    
            //3.分配缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
    
            //4.发送数据到缓冲区
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()){
           
                String str = scanner.next();
                buf.put((new Date().toString()+"\n"+str).getBytes());
                buf.flip();
                sChannel.write(buf);
                buf.clear();
            }
            //5.关闭通道
            sChannel.close();
        }
    
  2. SocketChannel、ServerSocketChannel、DatagramChannel

7.Java NIO2(Path、Paths、Files)

你可能感兴趣的:(NIO,java)