JavaNIO中的Buffer详解
Java NIO的Buffer本质上是一个内存块,既可以写入数据,也可以从中读取数据。Java NIO中代表缓冲区的Buffer类是一个抽象类,位于java.nio包中,与普通的内存块(Java数组)不同的是:NIO Buffer对象提供很多实用的方法,用来进行写入和读取的交替访问。
分类
Buffer类是一个抽象类,对应于Java的主要数据类型。在NIO中,有8种缓冲区类,ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer、MappedByteBuffer。前7种Buffer类型覆盖了能在IO中传输的所有Java基本数据类型,第8种类型是一种专门用于内存映射的ByteBuffer类型。
Buffer类中重要的属性
在Buffer的读写过程中,常常伴随着对几个属性的修改:position、limit、capacity、mark。读写模式下,这几个属性代表不同的含义。其中capacity是创建缓存区的时候指定的,已经定义则不会再修改。其他的三个属性不能大于capacity,否则会抛出缓冲区溢出的异常。其他三个属性的含义如下:
- position:代表当前操作(读/写)的位置;
- limit:代表当前操作(读/写)的限制位置,不能超过这个位置;
- mark:用于临时记录当前的position,用于reset方法。
写缓存
写缓存是创建缓存区后的默认模式,此时limit和capacity是同一个位置,position指向0,mark默认-1。
当插入一个数据后,position加1后移,但是不能超过limit。
读缓存
当调用flip()
方法后,缓存进入读模式,此时limit变为position,而position变为0,此时可以读的数据在0-limit的范围。
1 | public final Buffer flip() { |
缓存的读模式进入缓存的写模式,可以通过两种方法clear()
和compact()
,前者直接将position置为0,limit置为capacity,写数据的时候,缓存中的数据将会被覆盖,第二种方法,则会将position和limit之间的数据重新拷贝到缓存的头部,不会丢数据。
remark的标记,将当前正操作的position临时保存,当调用reset()
的时候,会把remark中的值恢复到position中,相当于可以重新读取数据。
Buffer类的常用方法
常用的方法:创建,写,读,重复读,标记,重置。
缓存的创建
直接调用不同缓存类型的allocate()
方法,制定大小即可。
1 | IntBuffer intBuffer = IntBuffer.allocate(10); |
写缓存
调用put()
方法,将数据放到缓存中,如:
1 | for (int i = 0; i < 8; i++) { |
结果为:
1 | [put数据后]buffer的各个属性: position=8 limit=10 capacity=10 数据:[1, 2, 3, 4, 5, 6, 7, 8, 0, 0] |
读缓存
首先调用flip()
切换到读模式,然后调用get()
方法读取数据:
1 | // 调用flip切换读缓存模式,flip之前get的数据可能是脏数据 |
结果如下:
1 | [flip后]buffer的各个属性: position=0 limit=8 capacity=10 数据:[1, 2, 3, 4, 5, 6, 7, 8, 0, 0] |
重复读
调用rewind()
方法,将position置为0,重新读取数据。
结果:
1 | [rewind后]buffer的各个属性: position=0 limit=8 capacity=10 数据:[1, 2, 3, 4, 5, 6, 7, 8, 0, 0] |
读切换到写模式
clear方法:
1 | intBuffer.clear(); |
结果:
1 | [clear后]buffer的各个属性: position=0 limit=10 capacity=10 数据:[1, 2, 3, 4, 5, 6, 7, 8, 0, 0] |
compact方法:
1 | intBuffer.compact(); |
结果:
1 | [compact后]buffer的各个属性: position=6 limit=10 capacity=10 数据:[3, 4, 5, 6, 7, 8, 7, 8, 0, 0] |
两者的区别:compact拷贝剩余数据,而clear只变了位置。
标记重置
remark()
和reset()
方法组合使用:
1 | // remark记录位置 记录的position为6 |
结果:
1 | [reset前]buffer的各个属性: position=8 limit=10 capacity=10 数据:[3, 4, 5, 6, 7, 8, 10, 11, 0, 0] |