• java.nio.Buffer 中的 flip()方法


    在Java NIO编程中,对缓冲区操作常常需要使用  java.nio.Buffer中的 flip()方法。

      Buffer 中的 flip() 方法涉及到 Buffer 中的capacity、position、limit三个概念。

           capacity:在读/写模式下都是固定的,就是我们分配的缓冲大小(容量)。

           position:类似于读/写指针,表示当前读(写)到什么位置。

           limit:在写模式下表示最多能写入多少数据,此时和capacity相同。在读模式下表示最多能读多少数据,此时和缓存中的实际

                       数据大小相同。

    flip():Buffer有两种模式,写模式和读模式。在写模式下调用flip()之后,Buffer从写模式变成读模式。      

    那么limit就设置成了position当前的值(即当前写了多少数据),postion会被置为0,以表示读操作从缓存的头开始读,mark置为-1。

    也就是说调用flip()之后,读/写指针position指到缓冲区头部,并且设置了最多只能读出之前写入的数据长度(而不是整个缓存的容量大小)。

    例子分析,这三个属性的作用

    1.分配内存大小为10的缓存区。索引10的空间是我虚设出来,实际不存在,为了能明显表示capacity。IntBuffer的容量为10,所以capacity为10,在这里指向索引为10的空间。Buffer初始化的时候,limit和capacity指向同一索引。position指向0。

    这里写图片描述

    2.往Buffer里加一个数据。position位置移动,capacity不变,limit不变。

    这里写图片描述

    3.Buffer读完之后,往bufer里写了5个数据,position指向索引为5的第6个数据,capacity不变,limit不变。

    这里写图片描述

    4.执行flip()。这时候对照着,之前flip源码去看。把position的值赋给limit,所以limit=5,然后position=0。capacity不变。结果就是: 
    这里写图片描述

    5.Buffer开始往外写数据。每写一个,position就下移一个位置,一直移到limit的位置,结束。

    这里写图片描述

    上图的顺序就是代码中的IntBuffer从初始化,到读数据,再写数据三个状态下,capacity,position,limit三个属性的变化和关系。 
    大家可以发现: 
    1. 0 <= position <= limit <= capacity 
    2. capacity始终不变

    图中很好的阐述了,Buffer读写切换的过程。即flip()的反转原理。接下来我们从代码中检测上面的分析过程。想一下下面代码打印的内容,然后执行一编代码看看对不对。

    flip()源码:

        public final Buffer flip() {
            limit = position;
            position = 0;
            mark = -1;
            return this;
        }
    
    public class NioTest {
        public static void main(String[] args) {
            // 分配内存大小为10的缓存区
            IntBuffer buffer = IntBuffer.allocate(10);
    
            System.out.println("capacity:" + buffer.capacity());
    
            for (int i = 0; i < 5; ++i) {
                int randomNumber = new SecureRandom().nextInt(20);
                buffer.put(randomNumber);
            }
    
            System.out.println("before flip limit:" + buffer.limit());
    
            buffer.flip();
    
            System.out.println("after flip limit:" + buffer.limit());
    
            System.out.println("enter while loop");
    
            while (buffer.hasRemaining()) {
                System.out.println("position:" + buffer.position());
                System.out.println("limit:" + buffer.limit());
                System.out.println("capacity:" + buffer.capacity());
                System.out.println("元素:" + buffer.get());
            }
        }
    }

    实例代码(借用Java编程思想P552的代码): 

     
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
     
    /**
     * 获取通道
     * 
     * 
     */
    public class GetChannel {
    	private static final int SIZE = 1024;
     
    	public static void main(String[] args) throws Exception {
    		// 获取通道,该通道允许写操作
    		FileChannel fc = new FileOutputStream("data.txt").getChannel();
    		// 将字节数组包装到缓冲区中
    		fc.write(ByteBuffer.wrap("Some text".getBytes()));
    		// 关闭通道
    		fc.close();
     
    		// 随机读写文件流创建的管道
    		fc = new RandomAccessFile("data.txt", "rw").getChannel();
    		// fc.position()计算从文件的开始到当前位置之间的字节数
    		System.out.println("此通道的文件位置:" + fc.position());
    		// 设置此通道的文件位置,fc.size()此通道的文件的当前大小,该条语句执行后,通道位置处于文件的末尾
    		fc.position(fc.size());
    		// 在文件末尾写入字节
    		fc.write(ByteBuffer.wrap("Some more".getBytes()));
    		fc.close();
     
    		// 用通道读取文件
    		fc = new FileInputStream("data.txt").getChannel();
    		ByteBuffer buffer = ByteBuffer.allocate(SIZE);
    		// 将文件内容读到指定的缓冲区中
    		fc.read(buffer);
    		buffer.flip();// 此行语句一定要有
    		while (buffer.hasRemaining()) {
    			System.out.print((char) buffer.get());
    		}
    		fc.close();
    	}
    }
    

      注意:buffer.flip();一定得有,如果没有,就是从文件最后开始读取的,当然读出来的都是byte=0时候的字符。通过buffer.flip();这个语句,就能把buffer的当前位置更改为buffer缓冲区的第一个位置。

  • 相关阅读:
    js简单的双向绑定
    angular的$scope
    angular一些冷门的用法
    堆栈
    angular一些有启发的博客
    160830、如何运用最新的技术提升网页速度和性能
    160829、Java加解密与数字签名
    160826、浏览器渲染页面过程描述,DOM编程技巧以及重排和重绘
    160825、互联网架构,如何进行容量设计?
    160824、ionic添加地图站点
  • 原文地址:https://www.cnblogs.com/gmhappy/p/11864095.html
Copyright © 2020-2023  润新知