NIO 学习

IO和NIO 区别:
1. IO面向流(stream),流是单向的,NIO面向的是(buffer),管道(channel)双向的。
2. IO是阻塞式,NIO是非阻塞式的(NIO多了一个选择器(selector))


缓冲区类型:
 ByteBuffer/CharBuffer/ShortBuffer/IntBuffer/LongBuffer/FloatBuffer/DoubleBuffer

缓冲区的四大属性:
capacity: 表示缓冲区最大的存取的容量,一旦申请,不能修改。
limit:表示缓冲区中可以操作的数据的大小。(limit后面的数据不能进行读写)。
postion: 表示缓冲区中正在操作的位置。
mark: 记录当前position的位置,可以通过reset()方法回到mark标记的位置。

position < limit < capacity;

put(): 存数据
flip(): 从写模式切换到读模式
get():取数据
rewind: 可重复读
clear:清空缓冲区,数据存于被遗忘的状态
isDirect: 是否是直接缓冲区

注意:分配缓存区分为直接缓存区(操作系统的直接内存上分配空间)和非直接缓冲区(JVM内存分配的
空间)
    

通道(channel)类型:
 用于源节点和目标节点的连接,在javaNIO中实现缓冲区的传输。
FileChannel:  本地文件的通道
SocketChannel: 网络文件的通道 TCP
ServerSocketChannel:网络文件的通道 TCP
DatagramChannel: 网络文件的通道 UDP

获取channel方法:
1. java 针对支持通道的类提供了 getChannel() 方法
 本地IO:
       FileInputStream/ FileOutputStream / RandomAccessFile

 网络IO:
       Socket/ ServerSocket/DatagramSocket
2. 在JDK1.7 中的NIO.2 针对各个通道提供了静态方法open() 获取通道
3. 在JDK1.7 中的NIO.2 的Files 工具类newByteChannel()


通道之间的数据传输:
   transferTo;
   transferFrom;
   ifc.transferTo(0, ifc.size(), ofc);
   ofc.transferFrom(ifc, 0,ifc.size());

分散(scatter)读取和聚集(gather)写入:
    将通道中数据读到多个缓冲区中;将多个缓冲区的数据写入通道中,通过buffer数组实现

扫描二维码关注公众号,回复: 5771148 查看本文章


非阻塞式适用于网络传输:
java.nio.channels.Channel
 |-- SelectableChannel
     |-- SocketChannel
      |-- ServerSocketChannel
       |-- DatagramChannel

        |-- Pipe.SinkChannel
         |-- Pipe.SourceChannel

阻塞式:
package com.nio.day02;

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;

import org.junit.Test;

public class TestBolckNIO {
    
    
    @Test
    public void client() throws IOException{
        // 获取通道
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress
("127.0.0.1",9898));
        FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"),
StandardOpenOption.READ);
        
        // 分配缓冲区
        ByteBuffer dst = ByteBuffer.allocate(1024);
        // 读取本地文件
        
        
        while(inChannel.read(dst) != -1){
            dst.flip();
            sChannel.write(dst);
            dst.clear();
        }
        
        inChannel.close();
        sChannel.close();
        
    }
    
    
    @Test
    public void server() throws IOException{
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
        ssChannel.bind(new InetSocketAddress(9898));
        
        FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"),
StandardOpenOption.WRITE,StandardOpenOption.CREATE);
        
        SocketChannel sChannel = ssChannel.accept();
        
        ByteBuffer buf = ByteBuffer.allocate(1024);
         
        while(sChannel.read(buf) != -1){
            buf.flip();
            outChannel.write(buf);
            buf.clear();
        }
        
        outChannel.close();
        sChannel.close();
        
        
    }
}

非阻塞式:

package com.nio.day01;

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

import org.junit.Test;

public class TestIO {
    
    // 客户端
    @Test
    public void client() throws IOException{
        // 获取通道
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
        // 切换成非阻塞模式
        sChannel.configureBlocking(false);
        //
        ByteBuffer buf = ByteBuffer.allocate(1024);
        buf.put((new Date()).toString().getBytes());
        buf.flip();
        sChannel.write(buf);
        buf.clear();
        
        sChannel.close();
    }
    
    @Test
    public void server() throws IOException{
        
        // 
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
        ssChannel.configureBlocking(false);
        ssChannel.bind(new InetSocketAddress(9898));
        
        // 创建选择器
        Selector seletor = Selector.open();
        
        // 监控选择器控制 通道的什么状态。
        ssChannel.register(seletor, SelectionKey.OP_ACCEPT);
        
        // 轮询式的获取选择器上已经"准备就绪"的事件
        while(seletor.select() > 0){
            // 获取当前选择器中的所有注册的选择键
            Iterator<SelectionKey> it = seletor.selectedKeys().iterator();
            
            while(it.hasNext()){
                // 获取准备就绪的事件
                SelectionKey sk = it.next();
                
                // 判断什么事件准备就绪
                if(sk.isAcceptable()){
                    SocketChannel sChannel = ssChannel.accept();
                    sChannel.configureBlocking(false);
                    sChannel.register(seletor, SelectionKey.OP_READ);
                }else if(sk.isReadable()){
                    SocketChannel sChannel = (SocketChannel)sk.channel();
                    
                    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();
                    }
                }
                
                // 取消选择键
                it.remove();
                
            }
        }
    }
}
 

猜你喜欢

转载自blog.csdn.net/baiguang1234/article/details/87987580