Java NIO(1):缓冲区

在新的IO中 所有数据的必须通过Channel传输 发送到Channel中的所有对象都必须先放入Buffer中 读取Channel中的对象也要先放入Buffer中

一个Buffer对象是固定数量的数据的容器 作用是一个存储器或分段运输区 在这里数据可被存储并在之后用于检索

对于每个非布尔原始数据类型都有一个缓冲区类

缓冲区倾向于处理字节

缓冲区是一个数组 可以理解成一个容器

缓冲区的属性:

1.容量(Capacity)

    能够容纳的数据元素的最大数量 缓冲区创建时被设定 之后不能被修改

2.上限(Limit)

    第一个不能被读写的元素 位于limit后的数据不能读写

3.位置(Position)

    下一个被读写的元素的索引 position的值恰好为读到了多少数据 新建一个Buffer对象 position为0 读取了2个 position为2 指向Buffer中第3个

4.标记(Mark)

    标记位置 调用mark()方法 mark=position reset() position=mark  标记在设定前是undefined

属性之间遵循的关系

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


Buffer的作用用于装入数据和输出数据


put()和get()


所有缓冲区都是可读的 但不是都是可写的

每个缓存区可以通过执行isReadOnly()来标示是否允许缓存区的内容被修改

对只读缓存区的修改会产生ReadOnlyBufferException


get和put的位置可以是相对(不带索引的)和绝对的

相对调用:

put()过多会导致位置超出上界 会抛出BufferOverflowException异常

get() 位置不小于上界 就会抛出BufferUnderflowException异常

绝对存取不会影响缓冲区的位置属性 但如果索引超出范围(负数或不小于上界) 会抛出IndexOutOfBoundsException异常


flip() = buffer.limit(buffer.position()).position(0) mark=-1

clear()  将缓存区重置为空状态 但它并没有改变缓存区中的任何数据元素 limit=capacity position=0 (恢复到最初状态) mark=-1

rewind()  position=0 mark=-1


compact():

将缓冲区的当前位置和界限之间的字节(如果有)复制到缓冲区的开始处
即将索引 p = position() 处的字节复制到索引 0 处 将索引 p + 1 处的字节复制到索引 1 处 
依此类推直到将索引 limit() - 1 处的字节复制到索引 n = limit() - 1 - p 处
然后将缓冲区的位置设置为 n+1 并将其界限设置为其容量

如果已定义了标记 则丢弃它



mark()和reset():

mark():设置Buffer的mark位置 只能在0到position之间做mark返回Buffer

reset() 将位置设置为mark所在的索引 position=mark


hasRemaining()和remaining()

hasRemaining:判断positio和limit之间是否有元素

remaining:返回positio和limit之间元素的个数


rewind():position设置为0 取消mark的设置


缓存区的比较:



比较方法中"剩余"的理解:



两者都不允许比较不同类型的Buffer

缓冲区的创建:

以CharBuffer为例:



1.CharBuffer charBuffer = CharBuffer.allocate(100); // 创建100个char容量的CharBuffer

2.char[] charArray = new char[100];

CharBuffer charBuffer = CharBuffer.wrap(charArray);

注意:数据元素会放在charArray中 这意味着通过put()函数造成的对缓冲区的改动会直接影响这个数组 对这个数组的任何

改动也会对这个缓冲区对象可见

CharBuffer charBuffer = CharBuffer.wrap(charArray,12,42); // 创建一个position=12 limit=42+12=54 容量为charArray.length的缓冲区

allocate()和wrap()创建的缓冲区都是间接缓冲区 间接缓冲区使用备份数组 




如果hasArray返回false 不要使用array()或arrayOffset函数 不然会抛出UnsupportedOperationException异常

案例:

package com.tony.app;

import java.nio.CharBuffer;

public class CharBufferDemo {

	public static void main(String[] args) {
		// 创建CharBuffer
		CharBuffer charBuffer = CharBuffer.allocate(10);
		System.out.println("capacity:" + charBuffer.capacity());
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		
		// 存放数据
		charBuffer.put("Hello");
		System.out.println("position:" + charBuffer.position());
		charBuffer.flip();
		System.out.println("执行flip之后");
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		
		// 获取数据
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get());
		System.out.println("获取三个数据之后");
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		charBuffer.clear();
		System.out.println("执行clear之后");
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		
	
	}

}

输出结果:

capacity:10
limit:10
position:0
position:5
执行flip之后
limit:5
position:0
H
e
l
获取三个数据之后
limit:5
position:3
执行clear之后
limit:10
position:0
package com.tony.app;

import java.nio.CharBuffer;

public class CharBufferDemo {

	public static void main(String[] args) {
		// 创建CharBuffer
		CharBuffer charBuffer = CharBuffer.allocate(10);
		System.out.println("capacity:" + charBuffer.capacity());
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		
		// 存放数据
		charBuffer.put("Hello");
		System.out.println("position:" + charBuffer.position());
		charBuffer.flip();
		System.out.println("执行flip之后");
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		
		// 获取数据
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get());
		System.out.println("获取三个数据之后");
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		charBuffer.compact();
		System.out.println("执行compact之后");
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get());
		System.out.println(charBuffer.get(0));
		System.out.println(charBuffer.get(1));
		
	
	}

}

输出结果:

capacity:10
limit:10
position:0
position:5
执行flip之后
limit:5
position:0
H
e
l
获取三个数据之后
limit:5
position:3
执行compact之后
limit:10
position:2
l
l
o
l
o

缓冲区的复制:


共享的理解:两个缓冲区中数据相同 容量相同 但每个缓冲区拥有各自的position limit mark 一个缓冲区内的数据元素的改变会反映在另外一个缓冲区上

如果原始的缓冲区为只读或为直接缓冲区 新的缓冲区将继承这些属性

复制一个缓冲区会创建一个新的Buffer对象 但不复制数据 共享数据


分割缓冲区:


slice()创建一个从原缓冲区的当前位置开始的新缓冲区 并且其容量是原始缓冲区的剩余元素容量(limit-position)

新的缓冲区与原始缓冲区共享一段数据元素子序列 新的缓冲区也会继承只读和直接的属性

subSequence()不是真正意义的分割 只是改变了position和limit

package com.tony.app;

import java.nio.CharBuffer;

public class CharBufferDemo {

	public static void main(String[] args) {
		// 创建CharBuffer
		CharBuffer charBuffer = CharBuffer.allocate(10);
		System.out.println("capacity:" + charBuffer.capacity());
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		
		// 存放数据
		charBuffer.put("Hello");
		System.out.println("position:" + charBuffer.position());
		System.out.println("limit:" + charBuffer.limit());
		
		// 分割缓存区
		CharBuffer charBuffer_sub = charBuffer.slice();
		System.out.println("新的缓冲区");
		System.out.println("capacity:" + charBuffer_sub.capacity());
		System.out.println("limit:" + charBuffer_sub.limit());
		System.out.println("position:" + charBuffer_sub.position());
		
		// 再次存放数据到charBuffer
		charBuffer.put("tony");
		// 查看charBuffer_sub中的数据
		System.out.println(charBuffer_sub.get());
		System.out.println(charBuffer_sub.get());
		System.out.println(charBuffer_sub.get());
		System.out.println(charBuffer_sub.get());
		
		// subSequence分割缓存区
		charBuffer.clear();
		CharBuffer charBuffer_subSequence = charBuffer.subSequence(6, 8);
		System.out.println("capacity:" + charBuffer_subSequence.capacity());
		System.out.println("limit:" + charBuffer_subSequence.limit());
		System.out.println("position:" + charBuffer_subSequence.position());
	
	}

}

输出结果:

capacity:10
limit:10
position:0
position:5
limit:10
新的缓冲区
capacity:5
limit:5
position:0
t
o
n
y
capacity:10
limit:8
position:6

字节缓冲区(ByteBuffer):

所有的基本数据类型都有相应的缓冲区类 boolean除外 但字节缓冲区有独特之处

字节是操作系统和I/O设备 挡在JVM和OS间传递数据时 将其他的数据类型拆分成字节是必要的


多字节数值被存储在内存中的方式一般被称为endian-ness(字节顺序)

字节顺序:

大端和小端

大端:如果数字数值的最高字节位于低位地址 那么系统就是大端字节顺序

小端:大端反之

字节顺序很少由软件设计者决定 它通常取决于硬件设计

Intel处理器使用小端顺序

IP协议使用大端的网路字节顺序

在NIO中 字节顺序由ByteOrder类封装



toString返回大端或小端

每个Buffer类通过order方法返回当前字节的顺序




直接缓冲区:



视图缓冲区:


ByteBuffer类允许创建视图来讲byte类型Buffer映射为其它的原始数据类型

asLongBuffer():将Byte转化为long类型数据来存储的视图缓冲区


package com.tony.app;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;

public class CharBufferDemo {

	public static void main(String[] args) throws UnsupportedEncodingException {
		
		ByteBuffer byteBuffer = ByteBuffer.allocate(10); byteBuffer.order(ByteOrder.BIG_ENDIAN);
		CharBuffer charBuffer = byteBuffer.asCharBuffer();
		byteBuffer.put("tony".getBytes());
		System.out.println("capacity:" + byteBuffer.capacity());
		System.out.println("limit:" + byteBuffer.limit());
		System.out.println("position:" + byteBuffer.position());
		
		System.out.println("ByteBuffer==>CharBuffer");
		System.out.println("capacity:" + charBuffer.capacity());
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		
	}

}

capacity:10
limit:10
position:4
ByteBuffer==>CharBuffer
capacity:5
limit:5
position:0

package com.tony.app;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;

public class CharBufferDemo {

	public static void main(String[] args) throws UnsupportedEncodingException {
		
		ByteBuffer byteBuffer = ByteBuffer.allocate(10); byteBuffer.order(ByteOrder.BIG_ENDIAN);
		CharBuffer charBuffer = byteBuffer.asCharBuffer();
		byteBuffer.putChar('t');
		byteBuffer.putChar('o');
		byteBuffer.putChar('n');
		byteBuffer.putChar('y');
		
		System.out.println("ByteBuffer==>CharBuffer");
		System.out.println("capacity:" + charBuffer.capacity());
		System.out.println("limit:" + charBuffer.limit());
		System.out.println("position:" + charBuffer.position());
		System.out.println("CharBuffer:" + charBuffer.toString());
		
	}

}
ByteBuffer==>CharBuffer
capacity:5
limit:5
position:0
CharBuffer:tony

存取无符号数据

内存映射缓冲区(MappedByteBuffer)

P54-55


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值