java nio之Buffer(一)

    xiaoxiao2024-07-01  98

    Buffer是一个包装了基本数据元素数组的对象,它以及它的子类定义了一系列API用于处理数据缓存。 一、属性 Buffer有四个基本属性: 1、capacity  容量,buffer能够容纳的最大元素数目,在Buffer创建时设定并不能更改 2、limit buffer中有效位置数目 3、position 下一个读或者写的位置 4、mark  用于记忆的标志位,配合reset()使用,初始值未设定,调用mark后将当前position设为值 四者关系:0 <= mark <= position <= limit <= capacity 二、API package  java.nio; public   abstract   class  Buffer { public   final   int  capacity( ) public   final   int  position( ) public   final  Buffer position ( int  newPosition) public   final   int  limit( ) public   final  Buffer limit ( int  newLimit) public   final  Buffer mark( ) public   final  Buffer reset( ) public   final  Buffer clear( ) public   final  Buffer flip( ) public   final  Buffer rewind( ) public   final   int  remaining( ) public   final   boolean  hasRemaining( ) public   abstract   boolean  isReadOnly( ); } 支持链式调用,如:buffer.mark().position(5).reset( ); 注意isReadOnly()方法决定了buffer是否可写。 三、操作   以ByteBuffer为例, 1、访问,通过get(),get(index),其中get()从当前position位置读取,get(index)从index位置读取,不改变当前position,下面要说到的put也一样。 2、填充,通过put(byte),put(index,byte),按照绝对位置填充也是不改变当前position属性 3、flipping,试想,我们将填充完毕的buffer传递给socket输出,那么socket读取是依据position属性确定,就会从结尾后一位开始读,这样肯定是不正确的,如果要正确的读取我们先要:   buffer.limit(buffer.position( )).position(0); 将limit设为position, 将position设为0,这个操作就叫flipping,API直接提供了这个操作:   buffer.flip( ); 特别注意, flip()方法会改变limit属性,将limit属性从capacity设置为当前position。rewind()方法与flip()类似,但是仅将position设为0,而不改变limit,通常用于重新读取已经被flip的buffer。 flip()另一个注意点是,两次调用buffer的flip方法,将使得position和limit属性都为0。 4、迭代取元素: for  ( int  i  =   0 ; buffer.hasRemaining( ), i ++ ) { myByteArray [i]  =  buffer.get( ); } int  count  =  buffer.remaining( ); for  ( int  i  =   0 ; i  <  count, i ++ ) { myByteArray [i]  =  buffer.get( ); } ByteBuffer不是线程安全的,前一种方式适合并发访问,后一种方式效率更高。这两种方式都是一个一个取,效率都比批量取低。 5.clear()方法,将buffer重设为空状态,也就是设置limit=capacity,position=0,以便重复利用。 6.compact()方法,用于压缩buffer,这个方法在多次重复调用时是比较低效。 7.mark(),初始是未定义的,这适合如果调用reset将抛出InvalidMarkException。调用makr()后,将当前position设为mark以便reset时返回。注意,rewind( ), clear( ), and flip( )方法都将丢弃已经创建的mark。调用limit(index),positioon(index),如果index的值小于当前mark,mark也将被丢弃。 8.比较,可以通过equals()和compateTo()方法来比较两个buffer,前一个返回boolean,后一个返回0,-1,1。两个buffer equal的条件是: 1)类型相同 2)剩余元素的数目相等 3)剩余元素也一一相等 9、批量移动数据,为了更有效地进行数据传送,批量的数据存取肯定是不能少的,Buffer及其子类都有提供类似的方法,比如CharBuffer: public  CharBuffer get ( char  [] dst) public  CharBuffer get ( char  [] dst,  int  offset,  int  length) public   final  CharBuffer put ( char [] src) public  CharBuffer put ( char  [] src,  int  offset,  int  length) public  CharBuffer put (CharBuffer src) public   final  CharBuffer put (String src) public  CharBuffer put (String src,  int  start,  int  end)

    四、创建Buffer     Buffer以及其子类都无法直接new,而必须把通过他们提供的工厂方法来创建。通常有两种方式: 1、allocate,例如 CharBuffer charBuffer = CharBuffer.allocate (100); 将在堆上分配一个可以存储100个字符的数组作为backing store。 2、wrap,包装一个已有的数组: char [] myArray = new char [100]; CharBuffer charbuffer = CharBuffer.wrap (myArray); 注意,这样的方式创建的Buffer,将不会在堆上创建新的数组,而是直接利用myArray做backing store,这意味着任何对myArray或者buffer的修改都将影响到buffer或者myArray。可以通过public final boolean hasArray( )方法来判断是否拥有一个数组,通过array()方法取得这个数组。 五、复制Buffer    其实这个复制也是“浅拷贝”,通过duplicate()方法将返回一个新创建的buffer,这个新buffer与原来的Buffer共享数据,一样的capacity,但是有自己的position、limit和mark属性。通过asReadOnlyBuffer()方法复制的buffer与duplicate()类似,但是是只读的,不能调用put。比较特别的是slice()方法,故名思议,类似切割一个Buffer出来,与duplicate类似,但是它将从原来Buffer的当前position开始,并且capacity等于原来Buffer的剩余元素数目,也就是(limit-position)。

    文章转自庄周梦蝶  ,原文发布时间2008-02-22

    最新回复(0)