1、概述

1、nio核心:
		Channels    管道
		Buffers		缓冲区
		Selectors   选择器
		
		数据从缓冲区写进管道,或者从管道读取到缓冲区
		Selector允许单线程处理多个 Channel,即一个线程对应一个Selector,而一个Selector对应多个Channels(向Selector注册Channel)
2、buffer三大属性:
		capacity	容量
		position	写数据时,代表当前的位置
					当从写模式切换到读模式时,position重置为0,从某个特定位置读
		limit		写数据时,limit=capacity,表示最多能写多少数据
					读数据时,表示最多能读多少数据,即你之前写了多少数据(<=capacity)
3、向buffer中写数据:
		从Channel写到Buffer。
		通过Buffer的put()方法写到Buffer里
       向buffer中读数据:
		从Buffer读取数据到Channel。
		使用get()方法从Buffer中读取数据
		
4、Scatter与Gather
	Scatter:
		指数据从一个channel读取到多个buffer中
		channel.read(buffer[])必须先填满前一个buffer,才能往下一个buffer写数据
	Gather:
		指数据从多个buffer写入到同一个channel
		channel.write(buffer[])	
		write()方法会按照buffer在数组中的顺序,将数据写入到channel,注意只有position和limit之间的数据才会被写入。
		因此,如果一个buffer的容量为128byte,但是仅仅包含58byte的数据,那么这58byte的数据将被写入到channel中
5、通道之间的数据传输
       在nio中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel传输到另外一个channel
   channel.transferFrom方法和transferTo方法

2、FileChannel

package nio.file;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;  
  
public class FileChannelDemo {  
	
	
    public static void main(String args[]) throws IOException{
    	
    	fileChannelWriteDemo();
    	fileChannelReadDemo();
    	
    }  
    public static void fileChannelWriteDemo() throws IOException{
    	//从缓冲区读进管道
    	String newData = "hello,everybody!";
    	
    	ByteBuffer buffer = ByteBuffer.allocate(1024);
    	buffer.clear();
    	buffer.put(newData.getBytes());
    	buffer.flip();
    	
    	FileOutputStream out = new FileOutputStream("E:/nomanager/temp/data.txt",true);
    	FileChannel channel = out.getChannel();
    	
    	
    	while(buffer.hasRemaining()) {
    	    channel.write(buffer);
    	}

    	out.close();
    	
    }
    
    public static void fileChannelReadDemo() throws IOException{
    	//解决中文乱码问题
        Charset charset = Charset.forName("UTF-8");
        CharsetDecoder decoder = charset.newDecoder();
        
        
        FileInputStream in = new FileInputStream("E:/nomanager/temp/data.txt");
        FileChannel channel = in.getChannel();  
        //初始化缓存区大小
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);  
        CharBuffer charBuffer = CharBuffer.allocate(1024); 
        
        //读取
        while(channel.read(byteBuffer)!=-1){  
        	//将写模式切换为读模式
            byteBuffer.flip();  
            decoder.decode(byteBuffer, charBuffer, false);  
            charBuffer.flip();  
            
            System.out.println(charBuffer); 
            
            //clear()与compact()方法
            //clear会清除所有包括未读的,而compact会将未读的置顶
            charBuffer.clear();  
            byteBuffer.clear();  
        }  
        
        in.close();  
    }
    
    
}  

3、SocketChannel与ServerSocketChannel

package nio.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ServerSocketChannelDemo {

	
	public static void main(String[] args) throws IOException {
		
		ServerSocketChannel channel = ServerSocketChannel.open();
		
		channel.socket().bind(new InetSocketAddress(8080));
		//设置为非阻塞式
		channel.configureBlocking(false);
		
		while(true){
		    SocketChannel socketChannel = channel.accept();
		
		    if(socketChannel!=null){
		    	System.err.println("监听到了一个新连接!");
		    }

		}

	}
}
package nio.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;

public class SocketChanelDemo {

	
	public static void main(String[] args) throws IOException {
		
        
		SocketChannel channel = SocketChannel.open();
		boolean b = channel.connect(new InetSocketAddress("127.0.0.1",8080));
		
		
		System.err.println("连接结果:"+b);
		
		
		
		
		
	}
}

4、Selector

package nio;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class SelectorDemo {

	
	public static void main(String[] args) throws IOException {
		//创建一个Selector
		Selector selector = Selector.open();
		
		//创造5个管道(相当于这是服务器,来监听5个客户端连接)
		SocketChannel channel=SocketChannel.open();
		SocketChannel channe2=SocketChannel.open();
		SocketChannel channe3=SocketChannel.open();
		SocketChannel channe4=SocketChannel.open();
		SocketChannel channe5=SocketChannel.open();
		
		//与Selector一起使用时,Channel必须处于非阻塞模式下。这意味着不能将FileChannel与Selector一起使用,
		//因为FileChannel不能切换到非阻塞模式。而套接字通道都可以
		channel.configureBlocking(false);
		channe2.configureBlocking(false);
		channe3.configureBlocking(false);
		channe4.configureBlocking(false);
		channe5.configureBlocking(false);
		
		//感兴趣的事件
		int ops = SelectionKey.OP_ACCEPT | SelectionKey.OP_CONNECT 
				| SelectionKey.OP_READ | SelectionKey.OP_WRITE; 
		
		//向selector注册管道
		channel.register(selector,ops);
		channe2.register(selector,ops);
		channe3.register(selector,ops);
		channe4.register(selector,ops);
		channe5.register(selector,ops);
		
		
		while(true) {
			//select()方法返回的int值表示有多少通道已经就绪
			int readyChannels = selector.select();
			if(readyChannels == 0){
				continue;
			} 
			//获取readyChannels的集合
			Set selectedKeys = selector.selectedKeys();
			Iterator keyIterator = selectedKeys.iterator();
			
			//遍历readyChannels的集合
			while(keyIterator.hasNext()) {
				
				SelectionKey key = (SelectionKey)keyIterator.next();
				
				if(key.isAcceptable()) {
					// a connection was accepted by a ServerSocketChannel.
				} else if (key.isConnectable()) {
				    // a connection was established with a remote server.
				} else if (key.isReadable()) {
				    // a channel is ready for reading
				} else if (key.isWritable()) {
				    // a channel is ready for writing
				}
				
				keyIterator.remove();
			}
		}

	}
}