Java NIO概述及要点摘录

#普通IO与NIO区别?

IO:按流处理数据,速度慢;普通IO;
NIO:按块处理数据,速度快;通过通道channel和缓冲区buffer作为基础的面向块的IO处理;

#通道channel和缓冲区buffer是什么?
通道和缓冲区是NIO的核心对象;
channel是对原有IO包中流的模拟,到任何目的地的数据都需要通过channel对象;字节
buffer是一个容器对象,发送给一个channel的所有对象都必须首先放到buffer中,同样,从channel中读取的数据都要读到buffer中,是不能直接从channel中读取数据的,只能通过buffer;
buffer是一个数据,常用的是字节数组ByteBuffer,缓冲区还提供了对数据的结构化访问,可以跟踪系统的读写进程;

#通道channel是对旧的IO流的模拟,那么通道与旧的io流的区别在哪里?
channel是双向的,可以同时读写,unix底层操作系统通道也是双向的;
旧的IO流是单向的;

#NIO的文件读写
读取文件步骤:从FileInputStream获取channel,创建Buffer,将数据从channel读到buffer中;
读文件:

FileInputStream fin = new FileInputStream("demo.txt");
FileChannel fc = fin.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
fc.read(buffer);

 

 写文件:

FileOutputStream fout = new FileOutputStream("demo.txt");
FileChannel fc - fout.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
for(int i=0; i< message.length; i++){
	buffer.put(message[i]);
}
buffer.flip();
fc.write(buffer);

#NIO读写时,我们不需要告诉通道要读多少数据到缓冲区中,每一个缓冲区都有复杂的内部统计机制,它会跟踪已经读了多少数据及还有多少空间可以容纳更多的数据,JDK中是如何设计和实现这个个机制的?(待深入研究.)

 

#缓冲区内部实现机制
缓冲区的两个重要实现组件:状态变量,访问方法;
每一种java基本类型的缓冲区都是对象类Buffer的子类;buffer有三个似有属性:
private int position = 0;//跟踪了向缓冲区中写入多少数据或者从缓冲区中读取了多少数据;
private int limit;//表明还有多少数据需要取出,或还有多少空间可以放入数据;
private int capacity;//该缓冲区的最大数据容量;
每个基本类型的缓冲区底层实上就是一个该类型的数组;例如ByteBuffer中的final byte[] nb;
从通道读取数据,实际上是将读取的数据放到该数组中,向通道中写入时,是将该数组中的数据写入到通道中;
#如何使用
使用缓冲区将数据从输入通道拷贝到输出通道:

while(true){
	buffer.clear();
	int r = fcin.read(buffer);
	if(r==-1){
		break;
	}
	buffer.flip();
	fcout.write(buffer);
}

 其中:clear(),flip()用于让缓冲区在读写之间切换;

 

#连网与异步IO
nio中的连网与nio中的其它操作无区别,仍然是依赖于通道和缓冲区,使用InputStream和OutputStream获取通道;
异步io调用不会阻塞。它的最大优势:允许同时根据大量的输入和输出执行IO,同步程序常常求助于轮询或者创建许多线程处理大量连接,使用异步IO,可以监听任何数量的通道上的事件,不用轮询,也不用额外的线程;

应用实例:基于非组赛io的服务器端的处理流程,它接收网络连接并向它们回响它们可能发送的数据。

private void execute () throws IOException { // 创建一个新的选择器
	Selector selector = Selector.open();
	// 打开在每个端口上的监听,并向给定的选择器注册此通道接受客户端连接的I/O事件。 
	for (int i = 0; i < ports.length; i++) {
		// 打开服务器套接字通道
		ServerSocketChannel ssc = ServerSocketChannel.open(); // 设置此通道为非阻塞模式
		ssc.configureBlocking(false);
		// 绑定到特定地址
		ServerSocket ss = ssc.socket();
		InetSocketAddress address = new InetSocketAddress(ports[i]); ss.bind(address);
		// 向给定的选择器注册此通道的接受连接事件 
		ssc.register(selector, SelectionKey.OP_ACCEPT); 
		System.out.println("Going to listen on " + ports[i]);
	}
	while (true) {
		// 这个方法会阻塞,直到至少有一个已注册的事件发生。
		// 当一个或者更多的事件发生时,此方法将返回所发生的事件的数量。 int num = selector.select();
		// 迭代所有的选择键,以处理特定的I/O事件。
		Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iter = selectionKeys.iterator();
    	SocketChannel sc;
    	while (iter.hasNext()) {
        	SelectionKey key = iter.next();
		if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) { 
			// 接受服务器套接字撒很能够传入的新的连接,并处理接受连接事件。 
			ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
			sc = ssc.accept();
			// 将新连接的套接字通道设置为非阻塞模式 
			sc.configureBlocking(false);
			// 接受连接后,在此通道上从新注册读取事件,以便接收数据。 
			sc.register(selector, SelectionKey.OP_READ);
			// 删除处理过的选择键
			iter.remove();
	            	System.out.println("Got connection from " + sc);
        	} else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
			// 处理读取事件,读取套接字通道中发来的数据。 
			sc = (SocketChannel) key.channel();
			// 读取数据
			int bytesEchoed = 0; 
			while (true) {
	                    echoBuffer.clear();
	                    int r = sc.read(echoBuffer);
	                    if (r == -1) {
	                        break;
			}
	                echoBuffer.flip();
	                sc.write(echoBuffer);
	                bytesEchoed += r;
	       }
	      System.out.println("Echoed " + bytesEchoed + " from " + sc); // 删除处理过的选择键
	      iter.remove();
	} 
    }
  } 
}

 

 #使用allocate()分配缓冲区

ByteBuffer buffer = ByteBuffer.allocate(1024);

 其中,allocate()方法分配一个具有指定大小的底层数组,同时包装到一个对象中,例如ByteBuffer;

 

#使用数组转换成缓冲区

byte array[] = new byte[1024];
ByteBuffer buffer = ByteBuffer.wrap(array);

 #缓冲区如何分片

 

实际上就是创建一个子缓冲区,新旧缓冲区的一部分共享数据;

ByteBuffer buffer = ByteBuffer.allocate(10);
for(int i=0; i<buffer.capacity(); i++){
	buffer.put((byte)i):
}
//分片
buffer.position(3);
buffer.limit(7);
ByteBuffer slice = buffer.slice();

 #如何创建只读缓冲区,及作用?

 

调用缓冲区的asReadOnlyBuffer()方法,将缓冲区转化为只读,只读缓冲区可以保护数据,使数据不被修改;

#直接和间接缓冲区
#内存映射文件IO

#将文件的前1024个字节映射到内存

MappedByteBuffer mbf = fc.map(FileChannel.MapModel.READ_WRITE, 0 , 1024);
<pre>
#分散,聚集IO 
读:
 <pre lang="java">
long read(ByeteBuffer[] dst);
long read(ByteBuffer[] dst, in offset, int length);

 

 写:

long write(ByeteBuffer[] dst);
long write(ByteBuffer[] dst, in offset, int length);

 

 

参考:《NIO学习总结.pdf》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值