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对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android之使用Http协议实现文件上传功能
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- spymemcached源码中Reactor模式分析
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序