一、NIO总共分为三大部分:
1、缓冲区:Buffer是所有的xxxBuffer类的父类,MappedByyteBuffer:映射的类,主要是映射系统中的内存。
缓存区分为两种,一种是直接缓冲区,另一种是非缓冲区。
缓存区有Buffer,ByteBuffer,LongBuffer,IntegerBuffer,FloatBuffer,DoubleBuffer。
非直接缓冲区主要存放在jvm缓存区中来拷贝
直接缓冲区--存在物理内存中。
2、选择器:poll模型是windows里面的,epoll是linux系统中的,select,kqueue是操作系统的。整个selector在构建的时候不是由java来构建的,而是由java语言调用c语言来是实现的,它的底层是系统的底层。
3、通道:NIO最关联的就是通道,而通道要和选择器的事件进行绑定。
二、关于Buffer的代码如下:
1、创建ByteBuffer的对象,这里不是new的,而是创建该对象时要分配内存:allocate代表分配一块内存空间,将ByteBuffer的对象指向内存空间里面去。单位是字节,代码如下:
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);System.out.println("position:"+byteBuffer.position());System.out.println("limit:"+byteBuffer.limit());System.out.println("capacity:"+byteBuffer.capacity());System.out.println("往bytebuffer里存放数据。。。");byteBuffer.put("A23abc一二三".getBytes());System.out.println("position:"+byteBuffer.position());System.out.println("limit:"+byteBuffer.limit());System.out.println("capacity:"+byteBuffer.capacity());
运行的结果如下:往缓存区里放数据只会导致position的大小会变,其他的不会变。
2、如何从缓存区中读数据
System.out.println("往bytebuffer里读取数据。。。");byteBuffer.flip();// 开启读取模式System.out.println("position:"+byteBuffer.position());System.out.println("limit:"+byteBuffer.limit());System.out.println("capacity:"+byteBuffer.capacity());//应用程序的一个缓存byte[] bytes = new byte[byteBuffer.limit()];//读取到缓存区中byteBuffer.get(bytes);System.out.println(newString(bytes, 0, bytes.length));
运行的结果如下:这时position置为0,limit的值和上次的position的值一样,把position的值赋给limit。一旦缓冲区的容量定下来以后,那么缓冲区的容量是不可变的。读的数据就是从0的位置到15的位置。
3、rewind方法:
System.out.println("往bytebuffer里重复读取数据。。。" );byteBuffer.rewind();System.out.println("position:"+byteBuffer.position());System.out.println("limit:"+byteBuffer.limit());System.out.println("capacity:"+byteBuffer.capacity());byte[] bytes2 = new byte[byteBuffer.limit()];byteBuffer.get(bytes2);System.out.println(newString(bytes2, 0, bytes.length));
运行的结果如下:rewind:重复读取,不加这个方法会报错,因为limit后面不能再读取数据了。这个方法的意思是重复读的意思。limit不会变,但是position会变为0。
4、clear方法:调用这个方法的意思又可以再进行写的操作。
System.out.println("清空缓存区。。。");byteBuffer.clear();//// 值不清空 下标清空System.out.println("position:"+byteBuffer.position());System.out.println("limit:"+byteBuffer.limit());System.out.println("capacity:"+byteBuffer.capacity());System.out.println((char) byteBuffer.get());
运行的结果如下:
小结总结:上面的缓冲区是普通的缓冲区,直接放到了jvm当中的。而缓存区是不停的再读数据,会覆盖。
5、分散读取聚集写入
可以分开去读,写是在一起写。
注意:在分配指定大小的缓冲区的时候,如果是直接缓冲区的话是直接写在内存中,不是写在jvm的工作缓存区的。如果用分散读取聚集写入的话,不能用直接的缓冲区的方式,应该用普通的方式来分配。
代码如下:
// 随机访问RandomAccessFile raf = new RandomAccessFile("d:/abc.txt", "rw");// 获取通信FileChannel channel = raf.getChannel();// 分配指定大小指定缓冲区//这两个缓冲区是连通的//buf2相当于是备用缓冲区ByteBuffer buf1 = ByteBuffer.allocate(6);ByteBuffer buf2 = ByteBuffer.allocate(10);// 分散读取ByteBuffer[] bufs = {buf1, buf2};channel.read(bufs);for (ByteBuffer buf : bufs) {// 切换成读模式buf.flip();}System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));System.out.println("-----------------------------");System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));System.out.println("-----------重复读取-------------");RandomAccessFile raf2 = new RandomAccessFile("d:/abc.txt", "rw");// 获取通道FileChannel channel2 = raf2.getChannel();channel2.write(bufs);raf2.close();raf.close();
运行的结果如下:
关于管道的代码如下:
package com.gerry.nio.demo.nio.channel;import java.io.*;import java.nio.*;import java.nio.channels.*;/*** 通道和流绑定* 普通的缓冲区是基于jvm的,直接缓冲区是基于内存的。*/public class FileInputProgram {static public void main( String args[] ) throws Exception {FileInputStream fin = new FileInputStream("d:/abc.txt");// 在jdk1.5之后可以通过文件的流对象获取通道FileChannel fc = fin.getChannel();// 创建缓冲区ByteBuffer buffer = ByteBuffer.allocate(1024);// 读取数据到缓冲区fc.read(buffer);buffer.flip();//判断是否已经读完while (buffer.remaining() > 0) {byte b = buffer.get();System.out.print(((char)b));}fin.close();}}
运行的结果如下:
package com.gerry.nio.demo.nio.channel;import java.io.*;import java.nio.*;import java.nio.channels.*;public class FileOutputProgram {static private final byte message[] = {'a','c','d','e'};static public void main( String args[] ) throws Exception {FileOutputStream fout = new FileOutputStream( "e:/abc.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 );fout.flush();fout.close();}}
运行的结果如下:
总结:上面的是关于nio的缓冲区和通道中常用的方法做了一个总结,明天继续写关于nio的selector的网络通信的应用以及netty的入门。