Java NIO(一)- Buffer

        从JDK1.4开始,java提供了一系列改进的IO处理(NIO:New IO),NIO可以替代标准的Java IO API,并且与标准的IO工作方式不同。

Java NIO 是一种同步非阻塞式IO

Java中与新IO相关的包如下:
        ➢ java.nio包:主要包含各种与Buffer相关的类。
        ➢ java.nio.channels包:主要包含与Channel和Selector相关的类。
        ➢ java.nio.charset包:主要包含与字符集相关的类。
        ➢ java.nio.channels.spi包:主要包含与Channel相关的服务提供者编程接口。
        ➢ java.nio.charset.spi包:包含与字符集相关的服务提供者编程接口。

New IO中的三个核心对象:Channel(通道)Buffer(缓冲)

  1. Channel是对传统的输入/输出系统的模拟,在新IO系统中所有的数据都需要通过通道传输
  2. Buffer可以被理解成一个容器,它的本质是一个数组发送到Channel中的所有对象都必须首先放到Buffer中,而从Channel中读取的数据也必须先放到Buffer中

New IO提供了支持非阻塞式输入/输出的Selector(选择器)类;

        选择器是一个可以监视多个事件通道的对象(例如:连接打开、数据到达等)。因此,单个线程可以监视多个通道的数据。

其余的组件,如 PipeFileLock只是与三个核心组件结合使用的实用程序类。

Buffer

Buffer是一个抽象类。

Buffer就像一个数组,它可以保存多个类型相同的数据,可以在底层字节数组上进行get/set操作。

Buffer的类型:
        CharBuffer
        byteBuffer(最常用,但也与其他Buffer有点不同)
        ShortBuffer
        IntBuffer
        LongBuffer
        FloatBuffer
        DoubleBuffer
(boolean类型没有对应的Buffer)

这些Buffer类都没有提供构造器,通过使用如下方法来得到一个Buffer对象。

static XxxBuffer allocate(int capacity):创建一个容量为capacity的XxxBuffer对象。(不同Buffer都有的类方法

Buffer中有三个重要的属性:容量(capacity)界限(limit)位置(position)

容量:Buffer相当于一个内存块,而容量就是这个内存块所能存储的该类型元素的数量,言外之意就是这个内存块的大小,容量不为负数且创建之后大小不能改变

界限:第一个不应该被读出或者写入的缓冲区的元素的位置索引。也就是说,位于limit后的数据既不可被读,也不可被写。限制永不为负数也永远不会大于容量。

位置:用于指明下一个可以被读出的或者写入的缓冲区位置索引(类似于IO流中的记录指针)。说明在position之前的缓冲区已经被使用,从position开始到limit之间的缓冲区未被使用。位置也永不为负数也永远不大于其界限。

0 <= mark <= position <= limit <= capacity

0-capacity:Buffer的空间大小

0-limit:表示Buffer中可以使用的空间大小

0-position:表示Buffer中已使用的空间大小

position-limit:表示buffer中可以使用但尚未使用的空间大小

(这里的大小指的是该Buffer对应的类型元素的数量;Buffer里还支持一个可选的标记(mark,类似于传统IO流中的mark),Buffer允许直接将position定位到该mark处。)

Buffer的主要作用就是装入数据,然后输出数据

创建Buffer:       

//创建大小为48个byte元素大小的ByteBuffer,capacity为48
ByteBuffer buf = ByteBuffer.allocate(48);

//从通道中映射一个大小为1024个char元素大小的CharBuffer,capacity为1024
CharBuffer buf = CharBuffer.allocate(1024);

使用Buffer通常遵循4个步骤:

1、数据装入Buffer

        开始时:Buffer的position为0,limit为capacity,程序可通过put()方法向Buffer中放入一些数据(或者从Channel中获取一些数据),每放入一些数据,Buffer的position相应地向后移动一些位置。

2、调用Buffer的flip()方法

        该方法将limit设置为position所在位置,并将position设为0,这就使得Buffer的读写指针又移到了开始位置。也就是说,Buffer调用flip()方法之后,Buffer为输出数据做好准备。

3、读取数据

        使用get()系列的方法读取数据。

4、调用Buffer的clear()方法或者compact()方法,为再次向Buffer中装入数据做好准备

        clear()方法清除(注意:这里的清除并不是字面意思)整个缓冲区,clear()方法不是清空Buffer的数据,它仅仅将position置为0,将limit置为capacity,这样为再次向Buffer中装入数据做好准备。

  compact() 方法仅清除注意:这里的清除并不是字面意思)已读取的数据。任何未读数据都被移到缓冲区的开头,数据将在未读数据之后写入缓冲区。

 Buffer中一些常用的方法(不完全):

➢ int capacity():返回Buffer的capacity大小。
➢ boolean hasRemaining():判断当前位置(position)和界限(limit)之间是否还有元素可供处理。
➢ int limit():返回Buffer的界限(limit)的位置。
➢ Buffer limit(int newLt):重新设置界限(limit)的值,并返回一个具有新的limit的缓冲区对象。
➢ Buffer mark():设置Buffer的mark位置,它只能在0和位置(position)之间做mark。
➢ int position():返回Buffer中的position值。
➢ Buffer position(int newPs):设置Buffer的position,并返回position被修改后的Buffer对象。
➢ int remaining():返回当前位置和界限(limit)之间的元素个数。
➢ Buffer reset():将位置(position)转到mark所在的位置。
➢ Buffer rewind():将位置(position)设置成0,取消设置的mark。

        Buffer的所有子类还提供了两个重要的方法:put()和get()方法,用于向Buffer中放入数据和从Buffer中取出数据。当使用put()和get()方法放入、取出数据时,Buffer既支持对单个数据的访问,也支持对批量数据的访问(以数组作为参数)。 

注意:

        使用put()和get()来访问Buffer中的数据时,分为相对和绝对两种。
相对(Relative):从Buffer的当前position处开始读取或写入数据,然后将位置(position)的值按处理元素的个数增加。(直接get())

绝对(Absolute):直接根据索引向Buffer中读取或写入数据,使用绝对方式访问Buffer里的数据时,并不会影响位置(position)的值。(get(int index),需要给出索引值index)

equals() 和 compareTo() :

        equals()compareTo()方法是用于比较两个缓冲区。
 

equals() 如果满足以下条件,则两个缓冲区相等:

  1. 它们的类型相同(字节、字符、整数等)
  2. 它们在缓冲区中具有相同数量的剩余字节、字符等(position要在相同的位置)。
  3. 所有剩余的字节、字符等都是相等的(position位置之后上的每一个元素也要相同)。

compareTo()  方法比较两个缓冲区的剩余元素(字节、字符等)

    注意:在以下情况下,缓冲区被认为比另一个缓冲区“小”:

  1. 依次比较剩余元素的大小,直至元素不相等,直接返回比较结果。
  2. 如果所有元素都是相等的,但第一个缓冲区在第二个缓冲区之前用完元素(它有更少的元素),那么第一个缓冲区小于第二个缓冲区。

猜你喜欢

转载自blog.csdn.net/qq_40100414/article/details/120390461