NIO常用操作
buffer(缓冲区)的常用操作
在Java NIO中负责数据的存取,缓冲区就是数组,用于存储不同类型的缓冲区。为什么说NIO是基于缓冲区的IO方式呢?因为,当一个链接建立完成后,IO的数据未必会马上到达,为了当数据到达时能够正确完成IO操作,在BIO(阻塞IO)中,等待IO的线程必须被阻塞,以全天候地执行IO操作。为了解决这种IO方式低效的问题,引入了缓冲区的概念,当数据到达时,可以预先被写入缓冲区,再由缓冲区交给线程,因此线程无需阻塞地等待IO。
- buffer中三个元素
- limit:界限,表示缓冲区中可以操作数据的大小(limit后数据不能进行读写)
- capacity:容量,表示缓冲区中最大数据的存储容量
- position:位置,表示缓冲区中正在操作数据的位置
2.常用API - ByteBuffer bb=ByteBuffer.allocate(1024)
非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中 - ByteBuffer bb=ByteBuffer.allocateDirect(1024)
直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率 - bb.put(“test”.getBytes())
存入数据,写操作,此时capacity=1024,limit=1024,position=4 - bb.flip()
读写切换操作,查看源码:
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
可以看出,它是将写的数据的位置(position=4)作为当前的limit,position置为0。所以现在的position=0,limit=4。
- bb.get()
byte[] by=new byte[bb.limit()];
bb.get(by);
读取数据,将数据读到byte数组,此时读取后,我们的position=limit=4,如果继续全量读取,那么会出现越界。那么怎么可以让数据重复读取呢? - bb.rewind()
是数据可重复读
我们来看一下他的源码:
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
很简单,只是将我们的position置为0,这样就可以重复读取了。
- bb.clear()
清空缓冲区,但是缓冲区的数据依然存在,我们来看一下源码:
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
可以看出,相当于将所有的变量的值恢复到刚创建的那一刻,limit=capacity,position=0,mark=-1。所以这里的clear可能和我们想象的不一样,此时缓冲区的数据还是存在的。
最后我们再说说mark(),mark通常和reset是一起使用的,
- mark()
标记当前所在位置,我们看一下源码。
public final Buffer mark() {
mark = position;
return this;
}
将position付给mark,这个mark后面会有用。
- reset()
重置,我们还是看一下实现:
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
可以看出,reset必须在mark后使用,不然会报错,因为默认mark=-1,reset主要是将position恢复到我们mark的位置。
最后我们看一下效果
bb.rewind();
System.out.println((char)bb.get());
System.out.println("1:buffer position="+bb.position()+" limit="+bb.limit());
System.out.println(bb.mark());
System.out.println((char)bb.get());
System.out.println((char)bb.get());
System.out.println("2:buffer position="+bb.position()+" limit="+bb.limit());
bb.reset();
System.out.println("3:buffer position="+bb.position()+" limit="+bb.limit());
System.out.println((char)bb.get());
System.out.println((char)bb.get());
执行结果:
t
1:buffer position=1 limit=1024
java.nio.HeapByteBuffer[pos=1 lim=1024 cap=1024]
e
s
2:buffer position=3 limit=1024
3:buffer position=1 limit=1024
e
s
可以看出,我们标记–>重置后,会从我们标记的位置开始读取数据。
channel(通道)的常用操作
用于源节点与目标节点的连接,在java NIO 中负责缓冲区中的数据传输,Channel本身不存储数据,因此需要缓冲区配合进行传输,通道就相当于铁轨,缓冲区就相当于火车。
引用 Java NIO 中权威的说法:通道是 I/O 传输发生时通过的入口,而缓冲区是这些数 据传输的来源或目标。对于离开缓冲区的传输,您想传递出去的数据被置于一个缓冲区,被传送到通道。对于传回缓冲区的传输,一个通道将数据放置在您所提供的缓冲区中。
转载于: Java NIO及其常用API