java nio(一)--Buffer基础
来源:互联网 发布:星际淘宝主微盘 编辑:程序博客网 时间:2024/05/18 02:46
一、什么是缓冲区
Java的NIO中Buffer至关重要:buffer是读写的中介,主要和NIO的通道交互。数据是通过通道读入缓冲区和从缓冲区写入通道的。
缓冲区buffer的本质就是一块可以读写的内存块(buffer类内部是一个基本数据类型的数组)。这块内存块被包装成NIO的Buffer对象,并提供了一组方法方便读写。
对于每个非布尔原始数据类型都有一个缓冲区类。
二、Buffer的家族
Buffer是顶层抽象类,另外还有八个基本数据抽象类。
MappedByteBuffer是ByteBuffer的一个具体实现类。
三、Buffer的属性
3.1、容量capacity
capacity是缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,并且永远不能被改变。
3.2、上界limit
缓冲区的第一个不能被读或写的元素。或者说,缓冲区中现存元素的计数。
3.3、位置position
下一个要被读或写的元素的索引。位置会自动由相应的get( )和put( )函数更新。
3.4、标志mark
一个备忘位置。调用mark( )来设定mark = postion。调用reset( )设定position = mark。标记在设定前是未定义的(undefined)。
四、Buffer API
4.1、创建一个容量大小为10的字符缓冲区
//新创建的容量为10的ByteBufferByteBuffer bf = ByteBuffer.allocate(10);
4.2、存取put() get()
put()和get()方法并没有在Buffer API中,而是在子类中定义的。这是因为每一个Buffer类所采用的参数类型,以及它们返回的数据类型,对每个子类来说都是唯一的,所以它们不能在顶层Buffer类中被抽象地声明。
看看ByteBuffer类的put() get()方法:
public abstract class ByteBuffer extends Buffer implements Comparable{// This is a partial API listing public abstract byte get( ); public abstract byte get (int index); public abstract ByteBuffer put (byte b); public abstract ByteBuffer put (int index, byte b);}
Get和put可以是相对的或者是绝对的,相对方案是不带有索引参数的函数。当相对函数被调用时,位置在返回时前进一。如果位置前进过多,相对运算就会抛出异常。对于put(),如果运算会导致位置超出上界,就会抛出BufferOverflowException异常。对于get(),如果位置不小于上界,就会抛出BufferUnderflowException异常。
4.3、填充
往缓冲区中put()五个字节:
bf.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'0');
ps:在java中,字符在内部以Unicode码表示,每个Unicode字符占16位。这里使用包含ascii字符集数值的字节。通过将char强制转换为byte,我们删除了前八位来建立一个八位字节值。这通常只适合于拉丁字符而不能适合所有可能的Unicode字符。
put()的绝对方案可以在不丢失位置的情况下进行一些更改:
bf.put(0,(byte)'M').put((byte)'w');
put(0,(byte)'M')将H换位M,且不改变position位置,依旧是5,put((byte)'w')才增加为6。
4.4、翻转flip()
如果把已经写满了缓冲区直接传递给一个通道,然后通道在缓冲区上执行get(),那么它将从刚刚插入的有用数据之外取出未定义数据。这时需要将位置值重新设为0,通道就会从正确位置开始获取。
但是它是怎样知道何时到达我们所插入数据末端的呢?这就是上界属性被引入的目的。
上界属性指明了缓冲区有效内容的末端。将上界属性设置为当前位置,然后将位置重置为0。
bf.limit(buffer.position()).position(0);
Buffer.flip()就是这个原理。
翻转后的缓冲区:
4.5、释放get()
布尔函数hasRemaining()会在释放缓冲区时告诉您是否已经达到缓冲区的上界。
以下是一种将数据元素从翻转后的缓冲区释放到一个数组的方法:
for (int i = 0; bf.hasRemaining( ), i++){myByteArray [i] = buffer.get( );}
remaining()函数将告知您从当前位置到上界还剩余的元素数目。
也可以通过下面的循环来释放翻转后的缓冲区:
int count = bf.remaining( );for (int i = 0; i < count, i++) {myByteArray [i] = buffer.get( );}
一旦缓冲区对象完成填充并释放,它就可以被重新使用了。Clear()函数将缓冲区重置为空状态。它并不改变缓冲区中的任何数据元素,而是仅仅将上界设为容量的值,并把位置设回0。
/** * 填充和释放缓冲区 * <p> * Created by w1992wishes on 2017/6/13. */public class BufferFillDrain { private static int index = 0; private static String[] strings = { "A random string value", "The product of an infinite number of monkeys", "Hey hey we're the Monkees", "Opening act for the Monkees: Jimi Hendrix", "'Scuse me while I kiss this fly", // Sorry Jimi ;-) "Help Me! Help Me!", }; public static void main(String[] args) { CharBuffer buffer = CharBuffer.allocate(100); while (fillBuffer(buffer)){ //缓冲区释放前先翻转 buffer.flip(); //翻转后再释放 drainBuffer(buffer); //释放后应重置指针 buffer.clear(); } } //释放 private static void drainBuffer(CharBuffer buffer) { while (buffer.hasRemaining()) System.out.print(buffer.get()); System.out.println(""); } //填充 private static boolean fillBuffer(CharBuffer buffer) { if (index >= strings.length) return false; String str = strings[index++]; Arrays.asList(str.toCharArray()) .stream() .forEach( c -> buffer.put(c) ); return true; }}
4.6、压缩compact()
public abstract class ByteBuffer extends Buffer implements Comparable {// This is a partial API listingpublic abstract ByteBuffer compact( );}
如果只想从缓冲区中释放一部分数据,而不是全部,然后重新填充。为了实现这一点,未读的数据元素需要下移以使第一个元素索引为0。尽管重复这样做会效率低下,但这有时非常必要,而API提供了一个compact()函数。这一缓冲区工具在复制数据时要比使用get()和put()函数高效得多。
bf.compact();
这里发生了几件事。
数据元素2-5被复制到0-3位置。
位置4和5不受影响,但现在正在或已经超出了当前位置,因此是“死的”。它们可以被之后的put()调用重写。
还要注意的是,位置已经被设为被复制的数据元素的数目。也就是说,缓冲区现在被定位在缓冲区中最后一个“存活”元素后插入数据的位置。
最后,上界属性被设置为容量的值,因此缓冲区可以被再次填满。调用compact()的作用是丢弃已经释放的数据,保留未释放的数据,并使缓冲区对重新填充容量准备就绪。
4.7、标记mark
标记,使缓冲区能够记住一个位置并在之后将其返回。
缓冲区的标记在mark( )函数被调用之前是未定义的,调用时标记被设为当前位置的值。
reset( )函数将位置设为当前的标记值。如果标记值未定义,调用reset( )将导致InvalidMarkException异常。
bf.position(2).mark().position(4);
bf.reset()
4.8、比较equlas()和compareTo()
所有的缓冲区都提供了一个常规的equals( )函数用以测试两个缓冲区的是否相等,以及一个compareTo( )函数用以比较缓冲区。
public abstract class ByteBuffer extends Buffer implements Comparable {// This is a partial API listingpublic boolean equals (Object ob)public int compareTo (Object ob)}
两个缓冲区可用下面的代码来测试是否相等:
if (buffer1.equals (buffer2)) { doSomething( ); }
如果每个缓冲区中剩余的内容相同,那么equals( )函数将返回true,否则返回false。
两个缓冲区被认为相等的充要条件是:
两个对象类型相同。包含不同数据类型的buffer永远不会相等,而且buffer绝不会等于非buffer对象。
两个对象都剩余同样数量的元素。Buffer的容量不需要相同,而且缓冲区中剩余数据的索引也不必相同。但每个缓冲区中剩余元素的数目(从位置到上界)必须相同。
在每个缓冲区中应被Get()函数返回的剩余数据元素序列必须一致。
两个相等的缓冲区
两个不相等的缓存区
缓冲区也支持用compareTo( )函数以词典顺序进行比较。这一函数在缓冲区参数小于,等于,或者大于引用compareTo( )的对象实例时,分别返回一个负整数,0和正整数。
这些就是所有典型的缓冲区所实现的java.lang.Comparable接口语义。
这意味着缓冲区数组可以通过调用java.util.Arrays.sort()函数按照它们的内容进行排序。
比较是针对每个缓冲区内剩余数据进行的,与它们在equals( )中的方式相同,直到不相等的元素被发现或者到达缓冲区的上界。如果一个缓冲区在不相等元素发现前已经被耗尽,较短的缓冲区被认为是小于较长的缓冲区。
4.9、批量移动
public abstract class CharBuffer extends Buffer implements CharSequence, Comparable {// This is a partial API listingpublic 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)}
有两种形式的get( )可供从缓冲区到数组进行的数据复制使用。
第一种形式只将一个数组作为参数,将一个缓冲区释放到给定的数组。
第二种形式使用offset和length参数来指定目标数组的子区间。
如果要求的数量的数据不能被传送,那么不会有数据被传递,缓冲区的状态保持不变,同时抛出BufferUnderflowException异常。因此当传入一个数组并且没有指定长度,就相当于要求整个数组被填充。如果缓冲区中的数据不够完全填满数组,会得到一个异常。这意味着如果想将一个小型缓冲区传入一个大型数组,需要明确地指定缓冲区中剩余的数据长度。
char [] bigArray = new char [1000];// Get count of chars remaining in the bufferint length = buffer.remaining( );// Buffer is known to contain < 1,000 charsbuffer.get (bigArrray, 0, length);
Put()的批量版本工作方式相似,但以相反的方向移动数据,从数组移动到缓冲区。
如果缓冲区有足够的空间接受数组中的数据(buffer.remaining()>myArray.length),数据将会被复制到从当前位置开始的缓冲区,并且缓冲区位置会被提前所增加数据元素的数量。如果缓冲区中没有足够的空间,那么不会有数据被传递,同时抛出一个BufferOverflowException异常。
- java nio(一)--Buffer基础
- JAVA NIO之Buffer(一)
- Java NIO - Buffer 基础 -1
- java.nio.Buffer缓冲区基础
- java nio之Buffer(一)
- java nio 基础(一)
- JAVA NIO 基础(一)
- java.nio包的分析(一)--Buffer类
- Java NIO源码剖析及使用实例(一):Buffer
- Java NIO:一、NIO基础
- java.nio基础篇之Buffer
- java nio 基础之Buffer 用法
- Java之NIO(一)Channel和Buffer
- Java 之NIO(一) - 简介(Buffer)
- JAVA NIO(一):Buffer.mark()的用法
- Java NIO(一) Buffer类源码分析
- java nio基础一
- Java NIO笔记(二):NIO Buffer(缓冲区)之基础
- Android Activity的生命周期
- 函数模板与函数重载
- AngularJS页面数据绑定设置默认值
- Synopsys DesignWareI2C master init
- 争当巡视反馈热烈欢呼第一人
- java nio(一)--Buffer基础
- linux延时函数
- python27在windows环境安装talib的方法
- xcode 插件开发
- node.js开发错误——DeprecationWarning: Mongoose: mpromise
- Appium之安装Carthage
- 腾讯实习内推
- 编译wireshark
- 升级Tensorflow到1.2版本