nio学习01-缓冲区

1.概念

缓冲区是包在一个对象内的基本数据元素数组。Buffer类似相比一个简单的数组优点是它将关于数据的数据内容和信息包含在一个单一的对象中。Buffer类似及它专有的子类定义了一个用于处理缓冲区的api。

他的本质是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成nio对象,并提供了一组方法,用来方便访问这块内存

jdk中的Buffer抽象类如下图:

2.缓冲区的分类

根据数据类型不同(boolean除外),提供了相应类型的缓冲区:

ByteBuffer

Charbuffer

ShortBuffer

IntegerBuffer

LongBuffer

FloatBuffer

DoubleBuffer

上面缓冲区的管理方式几乎一致,通过allocate()获取缓冲区

两个核心方法:

put()存入数据到缓存区

get():获取缓存区中的数据

3.四个属性

mark,position,limit,capacity

Capacity(容量):缓冲区能够容纳的数据的最大数量。这一容量在缓冲区创建时被设定,并且永远不能被改变。

Limit(上界):缓冲区的第一个不能被读或者被写的元素。或者说,缓冲区中现存元素的计数。

Position(位置):下一个要被读或者写的元素。位置会自动由相应的get()和put()方法函数更新。

Mark(标记):一个备忘位置。调用mark()来设定mark= position。调用reset()设定position=mark。标记在设定前是未定义的。

四个属性之间的关系

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

下面的图可以看一下:

4.直接缓冲区于非直接缓冲区:

非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在jvm的内存中。

非直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率。

5.code 测试

现在为写的模式

1.分配一个指定大小的缓冲区

                  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());

结果如下:

-----------------allocate()----------------
0
1024
1024

结果分析:

位置被设置为0,而且容量和上界被设置为1024,刚好经过缓冲区能够容纳的最后一个字节。

初始值以及初始位置

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());

结果如下:

-----------------put()----------------
5
1024
1024

结果分析:现在是写的模式position为下一个要写的位置所以是5,写的时候limit表示能往buffer里面写入多少数据。写模式下,limit=capiticy

3.切换读取数据模式

	        	buf.flip();
		System.out.println("-----------------flip()----------------");
		System.out.println(buf.position());
		System.out.println(buf.limit());
		System.out.println(buf.capacity());

结果如下:

-----------------flip()----------------
0
5
1024

调用flip()方法之后切换为读的模式position变为0,position新向前移动到下一个可读的位置。

切换到读的模式之后limit表示你最多能读多少数据,这里能读到的数据最多是5。

4.利用 get() 读取缓冲区中的数据

System.out.println("-----------------get()----------------");
		byte[] dst = new byte[buf.limit()];
		buf.get(dst);
		System.out.println(new String(dst, 0, dst.length));
		System.out.println(buf.position());
		System.out.println(buf.limit());
		System.out.println(buf.capacity());

结果如下:

-----------------get()----------------
abcde
5
5
1024

结果分析:

在调用了get方法以后posiotion的值变成了5,也就是limit的值。理解为从最开始开始读取数据,读到了最后一个字符。

现在我读到了数据的最后一个字符,现在想要再返回来读取怎么处理?下面引出他的rewind()方法

表示可重复读

5.rewind() : 可重复读

	                buf.rewind();
		
		System.out.println("-----------------rewind()----------------");
		System.out.println(buf.position());
		System.out.println(buf.limit());
		System.out.println(buf.capacity());

结果如下:

-----------------rewind()----------------
0
5
1024

结果分析:

数据又回到了最开始的数据位置。position变成了0。

rewind方法读写模式下都可以使用,它单纯的将当前位置置零,同时取消mark标记

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());

结果如下:

-----------------clear()----------------
0
1024
1024
a

和clear类似的还有一个方法,compact()方法

一旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear和compact方法来完成。

clear方法  position将被设置成0,limit被设置capacity。换句话说,buffer被清空了。buffer中的数据并未清除,只是这些告诉我们可以从哪里开始往Buffer里面写数据。

如果Buffer中有未读玩的数据,调用clear方法,数据将被遗忘,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。

如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先写入这些数据,那么调用compact方法。

compact方法将所有未读的数据拷贝到buffer起始处。然后将position设置到最后一个未读元素的后面。limit属性依然像clear方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。

发布了90 篇原创文章 · 获赞 11 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_35410620/article/details/103125369