Java - NIO之Buffer(下)

补:    Java - NIO之Buffer(上)


九、压缩

    如果从Buffer中读取了一部分数据之后仍有部分未读的数据,且后续还需要这些数据,但是此时想要先再写些数据,那么使用压缩

		/**
		 * 准备数据
		 */
		ByteBuffer buffer = ByteBuffer.allocate(10);
		buffer.put((byte)'M').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o').put((byte)'w');
		
		/**
		 * 翻转模式
		 */
		buffer.flip();
		
		/**
		 * 释放一部分('M'和'e'),剩下的保留
		 */
		for (int i = 0; i < 2; i++) {
			System.out.print((char)buffer.get());  
		}
		
		/**
		 * 释放之后,进行压缩(自动翻转为写的模式)
		 */
		buffer.compact();   
		
		/**
		 * 在剩下的部分的后面继续填充
		 */
		buffer.put((byte)'s');  
		
		/**
		 * 翻转模式
		 */
		buffer.flip();
		
		System.out.println();
		
		while (buffer.hasRemaining()) {
			System.out.print((char)buffer.get());
		}
    需要注意的是:
        当执行释放一部分('M'和'e')之后,如图:

            

        而执行compact()压缩操作,将所有未读的数据拷贝到Buffer起始处(第一个未读元素的索引为0),同时翻转为写模式,并将当前的位置(position)指定到未读数据元素的末尾,如下图所示:"llow"被拷贝,开始的'l'索引为0,position指向"llow"之后,至于位置4和5中对应的'o'和'w',因为现在正在或已经超出了当前位置,所以是死的,会被之后的put()所重写。

            


十、清理

    当Buffer中的数据被读取完了之后,需要让Buffer准备好再次被写入,通过clear()可以实现。

    调用的clear()之后,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。如果Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。


十一、Buffer比较之equals

    两个缓冲区被认为相等的充要条件是:

        两个对象类型相同。包含不同数据类型的buffer永远不会相等,而且buffer绝不会等于非buffer对象
        两个对象都剩余同样数量的元素(Buffer的容量不需要相同,而且缓冲区中剩余数据的索引也不必相同;但每个缓冲区中剩余元素的数目(从位置到上界)必须相同)
        在每个缓冲区中应被get()函数返回的剩余数据元素序列必须一致

		/**
		 * 准备数据
		 */
		ByteBuffer buffer1 = ByteBuffer.allocate(10);
		buffer1.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o');  //写入Hello
		ByteBuffer buffer2 = ByteBuffer.allocate(12);
		buffer2.put((byte)'A').put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o').put((byte)'Y');  //写入AHelloY
		
		/**
		 * 结果为true
		 * 因为1和2类型都为byte, 都还有5的空余(l-p)且空余的都是没有被填充的byte
		 * 所以比较的结果跟读写的模式也有关系
		 */
		System.out.println(buffer1.equals(buffer2));   
		
		buffer1.flip();
		buffer2.flip();

		/**
		 * 结果为false
		 */
		System.out.println(buffer1.equals(buffer2));
		
		/* p移动到H的位置 */
		buffer2.get();
		/* l设置为Y的位置(不包含Y了) */
		buffer2.limit(6); 
		/**
		 * 结果为true
		 */
		System.out.println(buffer1.equals(buffer2));
十二、Buffer比较之compareTo

    CompareTo是针对每个缓冲区内剩余数据进行的,与它们在equals()中的方式相同,直到不相等的元素被发现或者到达缓冲区的上界。如果一个缓冲区在不相等元素发现前已经被耗尽,较短的缓冲区被认为是小于较长的缓冲区。

		/**
		 * 准备数据
		 */
		ByteBuffer buffer1 = ByteBuffer.allocate(10);
		buffer1.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o');  //写入hello
		ByteBuffer buffer2 = ByteBuffer.allocate(12);
		buffer2.put((byte)'A').put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o').put((byte)'Y');  //写入AHelloY
		
		/**
		 * 结果:0
		 */
		System.out.println(buffer1.compareTo(buffer2));
		
		buffer1.flip();
		buffer2.flip();
		
		/**
		 * 结果:7
		 */
		System.out.println(buffer1.compareTo(buffer2));   
		
		/* p移动到H的位置 */
		buffer2.get();
		/* l设置为Y的位置(不包含Y了) */
		buffer2.limit(6); 
		
		/**
		 * 结果:0
		 */
		System.out.println(buffer1.compareTo(buffer2));

十三、批量读写

    如果所要求的数量的数据不能被传送,那么不会有数据被传递,缓冲区的状态保持不变,同时抛出BufferUnderflowException异常。

		/**
		 * 准备数据
		 */
		ByteBuffer buffer = ByteBuffer.allocate(10);
		buffer.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o');  
		
		buffer.flip();
		
		/**
		 * 等价为buffer.get(byteArr,0,byteArr.length);但是buffer不能提供byteArr长度的数据,所以BufferUnderflowException异常
		 */
		byte[] byteArr = new byte[10];
		buffer.get(byteArr);  
		
		/**
		 * 可以通过,buffer的状态将改变
		 */
		byte[] byteSmall = new byte[3];
		buffer.get(byteSmall);    
    如果您想将一个小型缓冲区传入一个大型数组,您需要明确地指定缓冲区中剩余的数据长度;如果缓冲区存有比数组能容纳的数量更多的数据,您可以重复利用数组读取。

		/**
		 * 准备数据
		 */
		ByteBuffer buffer = ByteBuffer.allocate(10);
		buffer.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o');  //写入hello
		
		buffer.flip();
		
		
		/**
		 * 小缓冲区数据传入大型数据 
		 */
		byte [] bigArray = new byte [15];
		
		// 通过remaining()获取缓冲区剩余的量
		int length = buffer.remaining();
		
		// 指定获取的量
		buffer.get(bigArray, 0, length);	
		
		for (int i = 0; i < bigArray.length; i++) {
			System.out.print((char)bigArray[i]);
		}
		
		
		System.out.println("-------------------");
		
		
		/**
		 * 重置位置,为测试方便
		 */
		buffer.position(0);
		
		
		/**
		 * 大缓冲区数据到小数组 
		 */
		byte[] smallArray = new byte[2];
		
		// 循环从buffer中读取
		while (buffer.hasRemaining()) {
			
			// smallArray长度的范围内,buffer最多还能提供多少量的数据
		    int slength = Math.min(buffer.remaining(), smallArray.length);
		    
		    // 从Buffer中读取
		    buffer.get(smallArray, 0, slength);
		    
		    //对获取的数据执行处理
		    for (int i = 0; i < smallArray.length; i++) {
				System.out.print((char)smallArray[i]);
				
				//清空已经处理的位置
				smallArray[i] = 0;  
			}
		}
    补充:put是类似的;另外,dstBuffer.put(srcBuffer);是两个缓冲区之前的传递,如果成功,两个缓冲区的状态都将改变


十四、复制缓冲区

    使用duplicate()用于创建一个与原始缓冲区相似的新缓冲区。

    两个缓冲区共享数据元素,拥有同样的容量,但每个缓冲区拥有各自的位置,上界和标记属性,但初始时是一样的。复制一个缓冲区会创建一个新的Buffer对象,但并不复制数据。原始缓冲区和副本都会操作同样的数据元素。

		/**
		 * 准备数据
		 */
		CharBuffer buffer = CharBuffer.allocate (8);
		buffer.put("abcdefgh");
		
		/**
		 * 执行之后,buffer的c为8,p为5,m为3,l为6
		 */
		buffer.position(3).limit(6).mark().position (5);
		
		// 
		/**
		 * 执行之后,dupeBuffer的c,p,m,l和buffer一样
		 */
		CharBuffer dupeBuffer = buffer.duplicate();
		
		//
		/**
		 * 复制完成之后,各自维护一份自己的四大c,p,m,l属性
		 */
		buffer.position(2);
		dupeBuffer.position(4);

十五、分割缓冲区

    使用slice()用于创建一个从原始缓冲区的当前位置开始的新缓冲区,并且其容量是原始缓冲区的剩余元素数量(limit-position)
    这个新缓冲区与原始缓冲区共享一段数据元素子序列。分割出来的缓冲区也会继承只读和直接属性

		/**
		 * 准备数据
		 */
		CharBuffer buffer = CharBuffer.allocate (8);
		buffer.put("abcdefgh");
		
		/**
		 * 设置属性
		 */
		buffer.position(2).limit(5);
		
		/**
		 * 分割
		 */
		CharBuffer sliceBuffer = buffer.slice();
		
		
		/**
		 * sliceBuffer只含有'c'、'd'和'e'
		 */
		for (int i = 0; sliceBuffer.hasRemaining(); i++) {
			System.out.print(sliceBuffer.get());
		}
		
		/**
		 * 修改 sliceBuffer的一个数据
		 */
		sliceBuffer.put(0, 'z');
		
		sliceBuffer.flip();
		
		System.out.println("");
		
		/**
		 * 'z'、'd'和'e'
		 */
		while(sliceBuffer.hasRemaining()){
			System.out.print((char)sliceBuffer.get());
		}
		
		System.out.println("");
		
		buffer.position(0).limit(8);
		
		/**
		 * a b z d e f g h
		 */
		while(buffer.hasRemaining()){
			System.out.print((char)buffer.get());
		}
十六、CharBuffer两个特殊的方法

		CharBuffer cb = CharBuffer.allocate(10);
		String str = "abcdefgh";

		/**
		 * 填充整个String字符串
		 */
		cb.put(str);
		
		cb.flip();
		
		/**
		 * a b c d e
		 */
		while (cb.hasRemaining()) {
			System.out.print(cb.get());
		}
		
		cb.clear();
		
		/**
		 * 填充String字符串中指定的开始和结束之间的字符
		 * str中第1到第3的字符 start -- end-1
		 */
		cb.put(str, 1, 4);  
		
		cb.flip();
		
		System.out.println();
		
		/**
		 * b c d
		 */
		for (int i = 0; cb.hasRemaining(); i++) {
			System.out.print(cb.get());
		}

附:ByteBuffer转String的方法

	public static String getString(ByteBuffer buffer) {
		Charset charset = null;
		CharsetDecoder decoder = null;
		CharBuffer charBuffer = null;
		try {
			charset = Charset.forName("UTF-8");
			decoder = charset.newDecoder();
			charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
			return charBuffer.toString();
		} catch (Exception ex) {
			ex.printStackTrace();
			return "";
		}
	}


 
  

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值