您的位置:首页 > Web前端

Java NIO学习——Buffer学习

2016-07-30 17:54 363 查看

概述

基本属性

一个缓冲区Buffer有四个属性,容量(Capacity),上界(limit),位置(position),标记(mark)。

属性名读模式含义写模式含义备注
容量(Capacity)Buffer的容量就是一个Buffer所最多能容纳的数据长度。同读模式Buffer在创建之后,容量便不会再变化
上界(limit)limit表示Buffer最多能读到多少数据。limit表示最多能往Buffer写入的数据量,此时,limit等于Buffer的capacity当切换Buffer到读模式时,limit会被设置成写模式下的position值;表示可读数据的结束位置
位置(position)position表示开始读取数据的位置,当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。当position=limit时,表示Buffer已无数据可读position表示当前待写入的位置。初始position值为0,当数据写入后,position会递增,position的max值为capacity – 1
标记(mark)mark(标记)是一个备忘位置,在初始化的时候,mark是未定义的值,在调用mark()函数后,设置mark=postion;等Buffer的position变化后,通过reset()函数,可以重新设置position=mark读写模式相同mark只是提供了一种position备份功能

Buffer模式

在Java中,一个缓冲区有两种模式,写模式(write mode)和读模式(Read Mode)。

当Buffer处于写模式的时候,表示当前Buffer等待写入数据,当一个Buffer初始化的时候,是处于写模式的。当Buffer达到容量最大值时,Buffer便不能再写入数据,如果继续写入,则会抛出BufferOverflowException异常,表示,Buffer已经写满。

当Buffer写完数据之后,可以切换到读模式,读模式表示可以从Buffer读取数据。如果Buffer内容已经读完,继续读取Buffer,则会抛出BufferUnderflowException异常。

模式切换函数

函数名作用
filp将Buffer从写模式切换到读模式
clear将Buffer从读模式切换到写模式,同时清空Buffer内所有数据
compact将Buffer从读模式切换到写模式,只清空已读数据,保留未读数据

例子

下面以CharBuffer为例看下Buffer基本读写方式,以及对应的属性。

public class LearnBuffer {
static void bufferP(){
CharBuffer charBuffer = CharBuffer.allocate(64);
System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
+", position:"+charBuffer.position());
charBuffer.append("This is a test.");
System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
+", position:"+charBuffer.position() );
System.out.println("\nBegin test read mode. ---------");
charBuffer.flip();
System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
+", position:"+charBuffer.position() );
System.out.print(charBuffer.get());
System.out.println(charBuffer.get());
System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
+", position:"+charBuffer.position() );
// mark当前位置
charBuffer.mark();
while (charBuffer.hasRemaining()){
System.out.print(charBuffer.get());
}
System.out.println();
try {
System.out.println(charBuffer.get());
}catch (java.nio.BufferUnderflowException e){
System.out.println("Get a java.nio.BufferUnderflowException.");
}

System.out.println("\nBegin test mark,reset. ---------");
// 将位置重置为之前mark的位置
charBuffer.reset();
System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
+", position:"+charBuffer.position() );
while (charBuffer.hasRemaining()){
System.out.print(charBuffer.get());
}
System.out.println();

System.out.println("\nBegin test compact. ---------");
// 将位置重置为之前mark的位置
charBuffer.reset();
// 将已读数据清除,保留未读数据
charBuffer.compact();
System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
+", position:"+charBuffer.position() );
charBuffer.flip();
while (charBuffer.hasRemaining()){
System.out.print(charBuffer.get());
}
System.out.println();

System.out.println("\nBegin test clear. ---------");
//读完数据之后,可以调用clear将Buffer切换到写模式,同时删除之前所有数据
charBuffer.clear();
System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
+", position:"+charBuffer.position() );
}

public static void main( String[] args ) throws IOException {
bufferP();
}
}


下面是上面程序的输出结果

Capacity:64, limit:64, position:0
Capacity:64, limit:64, position:15

Begin test read mode. ---------
Capacity:64, limit:15, position:0
Th
Capacity:64, limit:15, position:2
is is a test.
Get a java.nio.BufferUnderflowException.

Begin test mark,reset. ---------
Capacity:64, limit:15, position:2
is is a test.

Begin test compact. ---------
Capacity:64, limit:64, position:13
is is a test.

Begin test clear. ---------
Capacity:64, limit:64, position:0


创建缓冲区

Java语言提供了8种缓存区。除了MappedByteBuffer是内存映射,其他7种对应了Java的7种内置类型。7种对应内置类型的Buffer都是抽象类,不能直接用new进行实例化。这7个类提供了相应的静态工厂方法来创建相应的类。每个类的工厂方法名都是相同的。

Java提供了静态工厂方法,用于新建Buffer对象。

allocate 方法可以分配一个指定容量的Buffer,

wrap 会直接传入一个数组,则Buffer并不会再分配新的内存创建缓冲区,而是直接使用传入的数组作为缓存区,创建的Buffer类的capacity为数组的长度,使用Buffer类的操作,都会直接影响到传入的数组,比如,Buffer.put了一个字符,则可以直接通过数组得到。

public class LearnBuffer {
static void createBuffer(){
char[] chars = new char[64];
CharBuffer charBuffer = CharBuffer.wrap(chars);
System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
+", position:"+charBuffer.position() );
charBuffer.append('a');
System.out.println(chars[0]);
}

public static void main( String[] args ) {
createBuffer();
}
}


wrap 函数有两个版本,一个是直接传入一个数组,则buffer的position为0,limit为capacity;还有一种带有offset和length的版本,则buffer的position为offset,limit为length。

public class LearnBuffer {
static void createBuffer(){
char[] chars = new char[64];
CharBuffer charBuffer = CharBuffer.wrap(chars, 2, 16);
System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
+", position:"+charBuffer.position() );
charBuffer.append('a');
System.out.println(chars[2]);

CharBuffer charBuffer1 = CharBuffer.wrap(chars);
System.out.println("Capacity:"+charBuffer1.capacity()+", limit:"+charBuffer1.limit()
+", position:"+charBuffer1.position());
}

public static void main( String[] args ) {
createBuffer();
}
}


复制缓存区

duplicate 函数

duplicate()函数创建一个与原始缓冲区相似的新缓冲区,新缓冲区共享旧缓冲区的数据和容量,但却有自己的position和limit。

public class LearnBuffer {
static void duplicateBuffer(){
CharBuffer charBuffer = CharBuffer.allocate(64);
charBuffer.append("This is a duplicate test.");
System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
CharBuffer newBuffer = charBuffer.duplicate();
System.out.println("newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

charBuffer.flip();
System.out.println("After charBuffer flip, charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
System.out.println("After charBuffer flip, newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

System.out.println(charBuffer.get(0));
newBuffer.put(0, 'H');
System.out.println(charBuffer.get(0));
}

public static void main( String[] args ) {
duplicateBuffer();
}
}


asReadOnlyBuffer()函数生成一个只读的缓冲区,和duplicate函数一样,新的只读缓冲区,和之前缓冲区共享数据和容量,各自拥有自己的position和limit。但只读缓冲区是不能调用put函数,否则会抛出ReadOnlyBufferException异常。

public class LearnBuffer {
static void readOnlyBuffer(){
CharBuffer charBuffer = CharBuffer.allocate(64);
charBuffer.append("This is a readonly test.");

CharBuffer newBuffer = charBuffer.asReadOnlyBuffer();

System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
System.out.println("newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

charBuffer.flip();
System.out.println("After charBuffer flip, charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
System.out.println("After charBuffer flip, newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

try {
newBuffer.append('a');
}catch (ReadOnlyBufferException e){
System.out.println("Get an java.nio.ReadOnlyBufferException");
}
}

public static void main( String[] args ) {
readOnlyBuffer();
}
}


slice()函数也是产生新的缓冲区,并且与旧缓冲区共享数据,但slice()产生的缓冲区的容量是原缓冲区limit-position

static public void sliceBuffer(){
CharBuffer charBuffer = CharBuffer.allocate(64);
charBuffer.append("This is a slice test.");

CharBuffer newBuffer = charBuffer.slice();

System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
System.out.println("newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

charBuffer.append("Add new string.");
System.out.println(newBuffer.get(0));

System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
System.out.println("newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

charBuffer.flip();
CharBuffer newBuffer2 = charBuffer.slice();
System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
System.out.println("newBuffer2 capacity:"+newBuffer2.capacity()+", position:"+newBuffer2.position()+", limit:"+newBuffer2.limit());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java nio Buffer