中读写字节
分类:web前端

写字节:

Buffer 类

定义了一个可以线性存放primitive type数据的容器接口。Buffer主要包含了与类型(byte, char…)无关的功能。

值得注意的是Buffer及其子类都不是线程安全的。

每个Buffer都有以下的属性:

capacity
这个Buffer最多能放多少数据。capacity一般在buffer被创建的时候指定。

limit
在Buffer上进行的读写操作都不能越过这个下标。当写数据到buffer中时,limit一般和capacity相等,当读数据时,
limit代表buffer中有效数据的长度。

position
读/写操作的当前下标。当使用buffer的相对位置进行读/写操作时,读/写会从这个下标进行,并在操作完成后,
buffer会更新下标的值。

mark
一个临时存放的位置下标。调用mark()会将mark设为当前的position的值,以后调用reset()会将position属性设
置为mark的值。mark的值总是小于等于position的值,如果将position的值设的比mark小,当前的mark值会被抛弃掉。

这些属性总是满足以下条件:
0 <= mark <= position <= limit <= capacity

limit和position的值除了通过limit()和position()函数来设置,也可以通过下面这些函数来改变:

 

Buffer clear()

public final Buffer clear() {   
    position = 0;      //设置为0
    limit = capacity;    //极限和容量相同
    mark = -1;   //取消标记
    return this;   

把position设为0,把limit设为capacity,一般在把数据写入Buffer前调用。

 

Buffer flip()

public final Buffer flip() {   
     limit = position;    
     position = 0;   
     mark = -1;   
     return this;   

把limit设为当前position,把position设为0,一般在从Buffer读出数据前调用。

 

Buffer rewind()

public final Buffer rewind() {   
    position = 0;   
    mark = -1;   
    return this;   

把position设为0,limit不变,一般在把数据重写入Buffer前调用。

 

Buffer对象有可能是只读的,这时,任何对该对象的写操作都会触发一个ReadOnlyBufferException。
isReadOnly()方法可以用来判断一个Buffer是否只读

 

 

ByteBuffer 类

在Buffer的子类中,ByteBuffer是一个地位较为特殊的类,因为在java.io.channels中定义的各种channel的IO
操作基本上都是围绕ByteBuffer展开的。

ByteBuffer定义了4个static方法来做创建工作:

ByteBuffer allocate(int capacity) //创建一个指定capacity的ByteBuffer。
ByteBuffer allocateDirect(int capacity) //创建一个direct的ByteBuffer,这样的ByteBuffer在参与IO操作时性能会更好
ByteBuffer wrap(byte [] array)
ByteBuffer wrap(byte [] array, int offset, int length) //把一个byte数组或byte数组的一部分包装成ByteBuffer。

ByteBuffer定义了一系列get和put操作来从中读写byte数据,如下面几个:
byte get()
ByteBuffer get(byte [] dst)
byte get(int index)
ByteBuffer put(byte b)
ByteBuffer put(byte [] src)
ByteBuffer put(int index, byte b) 
这些操作可分为绝对定位和相对定为两种,相对定位的读写操作依靠position来定位Buffer中的位置,并在操
作完成后会更新position的值。在其它类型的buffer中,也定义了相同的函数来读写数据,唯一不同的就是一
些参数和返回值的类型。

除了读写byte类型数据的函数,ByteBuffer的一个特别之处是它还定义了读写其它primitive数据的方法,如:

int getInt()       //从ByteBuffer中读出一个int值。
ByteBuffer putInt(int value)     // 写入一个int值到ByteBuffer中。

读写其它类型的数据牵涉到字节序问题,ByteBuffer会按其字节序(大字节序或小字节序)写入或读出一个其它
类型的数据(int,long…)。字节序可以用order方法来取得和设置:
ByteOrder order() //返回ByteBuffer的字节序。
ByteBuffer order(ByteOrder bo)   // 设置ByteBuffer的字节序。

ByteBuffer另一个特别的地方是可以在它的基础上得到其它类型的buffer。如:
CharBuffer asCharBuffer()
为当前的ByteBuffer创建一个CharBuffer的视图。在该视图buffer中的读写操作会按照ByteBuffer的字节
序作用到ByteBuffer中的数据上。

用这类方法创建出来的buffer会从ByteBuffer的position位置开始到limit位置结束,可以看作是这段数据
的视图。视图buffer的readOnly属性和direct属性与ByteBuffer的一致,而且也只有通过这种方法,才可
以得到其他数据类型的direct buffer。

转自:

ByteBuffer前前后后看过好几次了,实际使用也用了一些,总觉得条理不够清晰。

    ByteBuffer 的capacity属性决定了它能容纳多少字节,这个属性不能改变。使用绝对put(int index, byte b)方法,可以改变ByteBuffer中任意位置的字节,下标index取值范围为【0,capacity-1】

《程序员的思维修炼》一本书讲过,主动学习,要比单纯看资料效果来的好,所以干脆写个详细点的文章来记录一下。

     ByteBuffer 中的字节数据也能通过相对put()方法来设置,该方法会用到缓冲区 position 和 limit 属性,即,该方法会改变缓冲区position处的字节,并把position值增加1。相对put(byte b)方法不能设置下标超过limit的字节数据(不管limit有没有小于capacity)。所以下面条件总是成立:  position<=limit<=capcity。下面是一个小例子。

概述

ByteBuffer是NIO里用得最多的Buffer,它包含两个实现方式:HeapByteBuffer是基于Java堆的实现,而DirectByteBuffer则使用了unsafe的API进行了堆外的实现。这里只说HeapByteBuffer。

// 创建一个空的容量为10个字节的ByteBuffer对象
ByteBuffer bbuf = ByteBuffer.allocate(10);

使用

ByteBuffer最核心的方法是put(byte)get()。分别是往ByteBuffer里写一个字节,和读一个字节。

值得注意的是,ByteBuffer的读写模式是分开的,正常的应用场景是:往ByteBuffer里写一些数据,然后flip(),然后再读出来。

这里插两个Channel方面的对象,以便更好的理解Buffer。

ReadableByteChannel是一个从Channel中读取数据,并保存到ByteBuffer的接口,它包含一个方法:

public int``read(ByteBuffer dst) ``throws``IOException;

 

WritableByteChannel则是从ByteBuffer中读取数据,并输出到Channel的接口:

public int``write(ByteBuffer src) ``throws``IOException;

 

那么,一个ByteBuffer的使用过程是这样的:

  1. byteBuffer = ByteBuffer.allocate(N);    //创建

  2. readableByteChannel.read(byteBuffer);   //读取数据,写入byteBuffer

  3. byteBuffer.flip();              //变读为写

4. writableByteChannel.write(byteBuffer);   //读取byteBuffer,写入数据

 

看到这里,一般都不太明白flip()干了什么事,先从ByteBuffer结构说起:

 

ByteBuffer的创建和读写

 

  1. ByteBuffer定义了4个static方法来做创建工作:

  ByteBuffer allocate(int capacity) //创建一个指定capacity的ByteBuffer。
  ByteBuffer allocateDirect(int capacity) //创建一个direct的ByteBuffer,这样的ByteBuffer在参与IO操作时性能会更好
  ByteBuffer wrap(byte [] array)
  ByteBuffer wrap(byte [] array, int offset, int length) //把一个byte数组或byte数组的一部分包装成ByteBuffer。

2. ByteBuffer定义了一系列get和put操作来从中读写byte数据,如下面几个:
  byte get()
  ByteBuffer get(byte [] dst)
  byte get(int index)
  ByteBuffer put(byte b)
  ByteBuffer put(byte [] src)
  ByteBuffer put(int index, byte b) 
    这些操作可分为绝对定位和相对定为两种,相对定位的读写操作依靠position来定位Buffer中的位置,并在操
  作完成后会更新position的值。在其它类型的buffer中,也定义了相同的函数来读写数据,唯一不同的就是一
  些参数和返回值的类型。

3. 除了读写byte类型数据的函数,ByteBuffer的一个特别之处是它还定义了读写其它primitive数据的方法,如:

  int getInt()             //从ByteBuffer中读出一个int值。
  ByteBuffer putInt(int value)  // 写入一个int值到ByteBuffer中。

  3.1 字节序

    读写其它类型的数据牵涉到字节序问题,ByteBuffer会按其字节序(大字节序或小字节序)写入或读出一个其它
  类型的数据(int,long…)。字节序可以用order方法来取得和设置:
  ByteOrder order() //返回ByteBuffer的字节序。
  ByteBuffer order(ByteOrder bo)   // 设置ByteBuffer的字节序。

  3.2 ByteOrder
    用来表示ByteBuffer字节序的类,可将其看成java中的enum类型。主要定义了下面几个static方法和属性:
    ByteOrder BIG_ENDIAN       代表大字节序的ByteOrder。
    ByteOrder LITTLE_ENDIAN 代表小字节序的ByteOrder。
    ByteOrder nativeOrder()       返回当前硬件平台的字节序。

 

4. ByteBuffer另一个特别的地方是可以在它的基础上得到其它类型的buffer。如:
  CharBuffer asCharBuffer()
    为当前的ByteBuffer创建一个CharBuffer的视图。在该视图buffer中的读写操作会按照ByteBuffer的字节
  序作用到ByteBuffer中的数据上。

    用这类方法创建出来的buffer会从ByteBuffer的position位置开始到limit位置结束,可以看作是这段数据
  的视图。视图buffer的readOnly属性和direct属性与ByteBuffer的一致,而且也只有通过这种方法,才可
  以得到其他数据类型的direct buffer。

// 获得该对象的 capacity 值
int capacity = bbuf.capacity(); // 10

ByteBuffer内部字段

// 使用绝对 put().
// 该方法不会影响到对象的position属性的值
bbuf.put(0,(byte)0xFF); // position=0

byte[] buff

buff即内部用于缓存的数组。

// 设置position
bbuf.position(5);

position

当前读取的位置。

读/写操作的当前下标。当使用buffer的相对位置进行读/写操作时,读/写会从这个下标进行,并在操作完成后,
buffer会更新下标的值。

// 使用相对 put(),会影响到position
bbuf.put((byte)0xFF);

mark

为某一读过的位置做标记,便于某些时候回退到该位置。

一个临时存放的位置下标。调用mark()会将mark设为当前的position的值,以后调用reset()会将position属性设
置为mark的值。mark的值总是小于等于position的值,如果将position的值设的比mark小,当前的mark值会被抛弃掉。

// 获得新的position值
int pos = bbuf.position(); // 6

capacity

初始化时候的容量。

这个Buffer最多能放多少数据。capacity一般在buffer被创建的时候指定。

// 获得从position到limit之间的元素数(注意在创建ByteBuffer对象时,limit=capacity,在本例中为10)
int rem = bbuf.remaining(); // 4

limit

在Buffer上进行的读写操作都不能越过这个下标。当写数据到buffer中时,limit一般和capacity相等,当读数据时,
limit代表buffer中有效数据的长度。

读写的上限,limit<=capacity。

 

这些属性总是满足以下条件:
  0 <= mark <= position <= limit <= capacity

limit和position的值除了通过limit()和position()函数来设置,也可以通过下面这些函数来改变:

Buffer clear()
  把position设为0,把limit设为capacity,一般在把数据写入Buffer前调用。

Buffer flip()
  把limit设为当前position,把position设为0,一般在从Buffer读出数据前调用。

Buffer rewind()
  把position设为0,limit不变,一般在把数据重写入Buffer前调用。

compact()

  该方法的作用是将 position 与 limit之间的数据复制到buffer的开始位置,复制后 position  = limit -position,limit = capacity

  但如果position 与limit 之间没有数据的话发,就不会进行复制  详细参考:java nio Buffer 中 compact的作用

mark()与reset()方法

  通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。例如:

  1.buffer.mark();

  2.//call buffer.get() a couple of times, e.g. during parsing.

  3.buffer.reset(); //set position back to mark

equals()与compareTo()方法

  可以使用equals()和compareTo()方法两个Buffer。

  equals()

  当满足下列条件时,表示两个Buffer相等:

  1. 有相同的类型(byte、char、int等)。
  2. Buffer中剩余的byte、char等的个数相等。
  3. Buffer中所有剩余的byte、char等都相同。

  如你所见,equals只是比较Buffer的一部分,不是每一个在它里面的元素都比较。实际上,它只比较Buffer中的剩余元素。

  compareTo()方法

  compareTo()方法比较两个Buffer的剩余元素(byte、char等), 如果满足下列条件,则认为一个Buffer“小于”另一个Buffer:

    1. 第一个不相等的元素小于另一个Buffer中对应的元素 。
    2. 所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。

Buffer对象有可能是只读的,这时,任何对该对象的写操作都会触发一个ReadOnlyBufferException。
isReadOnly()方法可以用来判断一个Buffer是否只读。

 

// 设置 limit的值
bbuf.limit(7); // remaining=1

图解

// 这个方法可以方便地将 position 置为 0
bbuf.rewind(); // remaining=7

put

写模式下,往buffer里写一个字节,并把postion移动一位。写模式下,一般limit与capacity相等。

 图片 1

 

flip

写完数据,需要开始读的时候,将postion复位到0,并将limit设为当前postion。 

读字节:

get

从buffer里读一个字节,并把postion移动一位。上限是limit,即写入数据的最后位置。

图片 2


clear

将position置为0,并不清除buffer内容。 

mark相关的方法主要是mark()(标记)和reset()(回到标记).

对应于上面每一个put方法,都有一个相应的get方法,这里不多说了。***

本文由10bet手机官网发布于web前端,转载请注明出处:中读写字节

上一篇:对象上创办非字节类型缓冲区,Java高端开垦 下一篇:java视频教程,我的J2EE成功之路
猜你喜欢
热门排行
精彩图文