nio(一)Buffer

1.简介

Buffer是一种用于特定的基本类型数据的容器,是特定的基本类型元素的线性、有限序列。

1.1 Buffer有四个相当重要的属性:

1)capacity:容量,Buffer所能够容纳的基本类型数据的数量。

2)mark:标记,Buffer中的一个位置

3)position:位置,下一个读写操作的元素在Buffer中的位置。

4)limit:限制,禁止读写操作的第一个元素的索引

1.2 四个属性之间的关系

0 <= 标记 <= 位置 <= 限制 <= 容量

1.3 影响四个属性的相关操作

1)public final Buffer mark()

在Buffer的位置设置标记

2)public final Buffer reset()

将Buffer的位置设置为之前的标记值,如果标志不存在则抛出InvalidMarkException

3)public final Buffer position(int newPosition)

设置Buffer的位置,如果标记已定义并且大于新的位置,则要丢弃该标记

newPosition范围[0,limit],否则抛出IllegalArgumentException

4)public final Buffer limit(int newLimit)

设置此缓冲区的限制。

如果位置大于新的限制,则它被设置为此新限制。

如果标记已定义并且大于新限制,则要丢弃该标记。

newPosition范围[0,capacity],否则抛出IllegalArgumentException

5)public final Buffer flip()

反转此缓冲区。

首先对当前位置设置限制,然后将该位置设置为零。

如果已定义了标记,则丢弃该标记。

效果等同于Buffer.limit(Buffer.position()); + Buffer.position(0);

6)public final Buffer rewind()

重绕此缓冲区。将位置设置为零并丢弃标记。

效果等同于Buffer.position(0);

7)public final Buffer clear()

清除此缓冲区。将位置设置为零,限制设置为该容量,并且丢弃标记。

注:此方法不能实际擦除缓冲区中的数据

效果等同于Buffer.limit(Buffer.capacity()); + Buffer.position(0);

8)put/get等当前位置存取方法均会使位置向前移动N个单位,存取操作的位置不能大于限制

9)put/get等绝对位置存取方法均不会改变Buffer的位置和限制

2.个人总结

1)关于写

Buffer通过position来控制读写操作的元素位置,每次写操作后都会将position向后移动写入数据的长度,因此一个连续的写操作的作用范围为从第1个写操作的position1到第N个写操作的positionN,即[position1, positionN+length(dataN))且0<=position1<positionN+length(dataN)<=limit。

2)关于读

由写的过程可知写的内容位于[position1, positionN+length(dataN))之间,所以读取写内容的时候也必须读取该范围的内容。

3)程序使用

程序使用Buffer时通过每次记录写操作的position1和positionN+length(dataN)不可行,因为可能对象A对Buffer进行写操作,并且只返回Buffer对象给需要读Buffer的对象B。

所以要利用Buffer的属性进行读写操作,使得

每次写操作开始前使postion=0,limit=capacity,这样写操作范围为[0, limit) = [0, capacity),即调用方法clear()

在写操作结束后读取内容前使limit=position,postion=0,这样读操作范围为[0, limit) = [position1, positionN+length(dataN)),即调用方法flip()

 第一次读取内容后要重复读取内容前只需使postion=0,这样读操作范围为[0, limit) = [position1, positionN+length(dataN)),即调用方法rewind()

3.实例

package com.siyuan.test.jdk.nio;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.InvalidMarkException;

public class BufferTest {
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		int BSIZE = 1024;
		ByteBuffer bBuffer = ByteBuffer.allocate(BSIZE);
		System.out.println("初始化...");
		System.out.println(getBufferStatus(bBuffer));
		bBuffer.putChar('a');
		System.out.println("在位置写入字符a后");
		System.out.println(getBufferStatus(bBuffer));
		bBuffer.mark();
		bBuffer.putChar('b');
		System.out.println("在位置设置标记,写入字符b后");
		System.out.println(getBufferStatus(bBuffer));
		int lastPosition = bBuffer.position(); //记录缓冲区有效字符的终结位置
		bBuffer.reset(); //效果等同于bBuffer.position(2);
		System.out.println("将位置设置为标志后");
		System.out.println(getBufferStatus(bBuffer));
		
		//读数据
		//设置位置,如果标记已定义并且大于新的位置,则要丢弃该标记
		bBuffer.position(lastPosition);
		/*
		 *将限制设置为位置,然后将位置设置为0,如果已定义了标记,则丢弃该标记
		 *常用于向buffer中写入数据后和从buffer中读取数据前 
		 *效果等同于 
		 *bBuffer.limit(bBuffer.position());
		 *bBuffer.position(0);
		 */
		bBuffer.flip(); 
		System.out.println("还原位置,flip后");
		System.out.println(getBufferStatus(bBuffer));
		while (bBuffer.hasRemaining()) {
			System.out.print(bBuffer.getChar());
		}
		System.out.println("读取完位置和限制之间的数据后");
		System.out.println(getBufferStatus(bBuffer));
		
		//重新读取
		/*
		 * 重绕此缓冲区。将位置设置为零并丢弃标记。
		 * 效果等同于
		 * Buffer.position(0);
		 */
		bBuffer.rewind();
		System.out.println("rewind后");
		System.out.println(getBufferStatus(bBuffer));
		while (bBuffer.hasRemaining()) {
			System.out.print(bBuffer.getChar());
		}
		System.out.println("读取完位置和限制之间的数据后");
		System.out.println(getBufferStatus(bBuffer));
		
		//重新写入数据
		/*
		 * 清除此缓冲区。将位置设置为零,限制设置为该容量,并且丢弃标记。
		 * 注:此方法不能实际擦除缓冲区中的数据
		 * 通过position和limit来确定有效数据的存储区域
		 * 效果等同于 
		 * bBuffer.limit(buffer.capacity());
		 * bBuffer.position(0);
		 */
		bBuffer.clear();
		System.out.println("clear后");
		System.out.println(getBufferStatus(bBuffer));
		bBuffer.putChar('b');
		bBuffer.putChar('b');
		bBuffer.putChar('c');
		bBuffer.putChar('c');
		System.out.println("在位置写入bbcc后");
		System.out.println(getBufferStatus(bBuffer));
		
		/*
		 * 绝对位置读取,不影响Buffer的属性
		 */
		System.out.println(bBuffer.getChar(4));
		System.out.println("在绝对位置4读取字符后");
		System.out.println(getBufferStatus(bBuffer));
		
		/*
		 * 绝对位置写入,不影响Buffer的属性,
		 * 且写入方式为覆盖,而不是插入
		 */
		bBuffer.putChar(4, 'd');
		System.out.println("在绝对位置4写入字符d后");
		System.out.println(getBufferStatus(bBuffer));
		
		System.out.println("重新读取Buffer的内容");
		bBuffer.flip();
		while (bBuffer.hasRemaining()) {
			System.out.print(bBuffer.getChar());
		}
	}
	
	public static final String getBufferStatus(Buffer buffer) {
		StringBuilder str = new StringBuilder();
		str.append("容量:").append(buffer.capacity())
			.append(",位置:").append(buffer.position())
			.append(",限制:").append(buffer.limit());
		boolean markExist = false;
		try {
			int position = buffer.position();
			buffer.reset();
			markExist = true;
			buffer.position(position);
		} catch(InvalidMarkException e) {
		}
		str.append(",存在标志: ").append(markExist);
		return str.toString();
	}
	
}

    运行结果:

初始化...
容量:1024,位置:0,限制:1024,存在标志: false
在位置写入字符a后
容量:1024,位置:2,限制:1024,存在标志: false
在位置设置标记,写入字符b后
容量:1024,位置:4,限制:1024,存在标志: true
将位置设置为标志后
容量:1024,位置:2,限制:1024,存在标志: true
还原位置,flip后
容量:1024,位置:0,限制:4,存在标志: false
ab读取完位置和限制之间的数据后
容量:1024,位置:4,限制:4,存在标志: false
rewind后
容量:1024,位置:0,限制:4,存在标志: false
ab读取完位置和限制之间的数据后
容量:1024,位置:4,限制:4,存在标志: false
clear后
容量:1024,位置:0,限制:1024,存在标志: false
在位置写入bbcc后
容量:1024,位置:8,限制:1024,存在标志: false
c
在绝对位置4读取字符后
容量:1024,位置:8,限制:1024,存在标志: false
在绝对位置4写入字符d后
容量:1024,位置:8,限制:1024,存在标志: false
重新读取Buffer的内容
bbdc

 4.参考资料

JDK文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值