关于NIO笔记(二):缓冲区Buffer
来源:互联网 发布:淘宝卖家如何借贷 编辑:程序博客网 时间:2024/05/23 01:11
使用Buffer读写数据一般遵循以下四个步骤:
- 写入数据到Buffer
- 调用
flip()
方法 - 从Buffer中读取数据
- 调用
clear()
方法或者compact()
方法
当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。
一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用clear()或compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。
为了理解Buffer的工作原理,需要熟悉它的五个属性:
- capacity
- position
- limit
- mark
- reset
position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。
capacity
作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。
position
当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.
当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。
limit
在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。
当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)
mark与reset
@Test
public void test1(){
String str = "abcde";
//1. 分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("-----------------allocate()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//2. 利用 put() 存入数据到缓冲区中
buf.put(str.getBytes());
System.out.println("-----------------put()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//3. 切换读取数据模式
buf.flip();
System.out.println("-----------------flip()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//4. 利用 get() 读取缓冲区中的数据
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println(new String(dst, 0, dst.length));
System.out.println("-----------------get()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//5. rewind() : 可重复读
buf.rewind();
System.out.println("-----------------rewind()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//6. clear() : 清空缓冲区. 但是缓冲区中的数据依然存在,但是处于“被遗忘”状态
buf.clear();
System.out.println("-----------------clear()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
System.out.println((char)buf.get());
}
@Test
public void test2(){
String str = "abcde";
//获取1024字节的存储空间
ByteBuffer buf = ByteBuffer.allocate(1024);
//存放
/**
* 二、缓冲区存取数据的两个核心方法:
* put() : 存入数据到缓冲区中
* get() : 获取缓冲区中的数据
*
*/
buf.put(str.getBytes());
//切换读写模式
buf.flip();
byte[] dst = new byte[buf.limit()];
/**get()源码
* public ByteBuffer get(byte[] dst, int offset, int length) {
checkBounds(offset, length, dst.length);
if (length > remaining())
throw new BufferUnderflowException();
int end = offset + length;
for (int i = offset; i < end; i++)
dst[i] = get();
return this;
}
*/
buf.get(dst, 0, 2);
System.out.println(new String(dst, 0, 2));//ab
System.out.println(buf.position());//2
//mark() : 标记
buf.mark();
buf.get(dst, 2, 2);
System.out.println(new String(dst, 2, 2));//cd
System.out.println(buf.position());//4
//reset() : 恢复到 mark 的位置
buf.reset();
System.out.println(buf.position());//2
//判断缓冲区中是否还有剩余数据
if(buf.hasRemaining()){
//获取缓冲区中可以操作的数量
System.out.println(buf.remaining());//3
}
}
- 字节缓冲要么是直接的,要么是非直接的。如果为直接字节缓冲区,则Java虚拟机会尽最大努力直接在缓冲区上执行本机I/O操作,也就是说,在每次调用基础操作系统的一个本机I/O操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中。
- 直接字节可以调用allocateDirect()工厂方法来创建,此方法返回的缓冲区进行分配和取消分配所需成本通常高于非直接缓存去。直接缓冲区的内容可以在驻留的垃圾回收堆之外,因此,他们对应用程序的内存需求量造成的影响可能并不明显,所以最好在直接缓冲区能在程序性能方面带来明显好处时分配他们。
- 直接字节缓冲去还可以通过fileChannel的map()方法将文件区域直接映射到内存中创建。该方法返回的是MappedByteBuffer。java平台的事项有助于通过JNI从本机代码创建直接字节缓冲区。如果以上这些缓冲区中的某一缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改缓冲区的内容,并且将会在访问期间或稍后的某一个时间导致抛出不确定的异常。
- 字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用isDirect()方法来确定。提供此方法是为了能够在性能关键型代码中执行显示缓冲区管理。
@Test
public void test3(){
/**
* * 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中
* 直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率
*/
//分配直接缓冲区
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
System.out.println(buf.isDirect());//true
}
- 关于NIO笔记(二):缓冲区Buffer
- Java NIO笔记(二):NIO Buffer(缓冲区)之基础
- 《Java NIO》学习笔记二 缓冲区(Buffer)
- NIO学习笔记之缓冲区Buffer
- Java NIO中的缓冲区Buffer(二)创建-复制缓冲区
- Java NIO中的缓冲区Buffer(二)创建-复制缓冲区
- Java NIO中的缓冲区Buffer(二)创建-复制缓冲区
- Java NIO中的缓冲区Buffer(二)创建-复制缓冲区
- Java NIO笔记(三):NIO Buffer(缓冲区)之进阶
- NIO - Buffer缓冲区
- NIO - Buffer缓冲区
- Java NIO学习总结二(Buffer缓冲区)
- Java-NIO(二):缓冲区(Buffer)的数据存取
- NIO学习笔记——缓冲区(Buffer)详解
- java.nio.Buffer缓冲区基础
- NIO —— 缓冲区Buffer
- NIO简介、缓冲区与Buffer
- java8 NIO 之缓冲区Buffer
- 关于CSS中hover失效的几个原因
- mysql主从复制
- Javascript 代码优化
- Java内省introspector
- cf 540-C. Ice Cave
- 关于NIO笔记(二):缓冲区Buffer
- RBAC打造通用web管理权限02
- Longest Common Prefix
- SSH学习之Struts2的环境搭建
- Javascript原型链
- 【模板】常用排序
- c语言程序设计现代方法---第四章:表达式
- git忽略文件和文件夹
- Java 类集框架