首页 > 其他 > 详细

NIO之Buffer

时间:2014-05-01 02:44:41      阅读:590      评论:0      收藏:0      [点我收藏+]

Buffer

 

Buffer

Mark<=Position <=Limt<=Capacity

状态变量

  • position:

在从通道读取时,将所读取的数据放到底层的数组中。 position 变量跟踪已经写了多少数据。它指定了下一个字节将放到数组的哪一个元素中。因此,如果从通道中读三个字节到缓冲区中,那么缓冲区的position 将会设置为3,指向数组中第四个元素。

  • mark:

 一个备忘标记位置调用,mark()函数设置mark=positon,调用reset()设置position=mark。

  • limit

limit 变量表明还有多少数据需要取出(在从缓冲区写入通道时),或者还有多少空间可以放入数据(在从通道读入缓冲区时)。

  • capacity

缓冲区的 capacity 表明可以储存在缓冲区中的最大数据容量。实际上,它指定了底层数组的大小或者指定了准许使用的底层数组的容量。

图形演示

初始:一个新创建的缓冲区。假设这个缓冲区的 总容量 为8个节。 Buffer 的状态如下所示:

bubuko.com,布布扣

  • 缓冲区:写入5个字节。Buffer 的状态如下所示:

 bubuko.com,布布扣

  • flip():它将设置limit为它将设置position为0;它将设置position为0;可以读缓冲区的内容了:

 bubuko.com,布布扣

  • 写入通道

第一次写入时,从缓冲区中取四个字节并将它们写入输出通道。这使得 position 增加到 4,而 limit 不变:

 bubuko.com,布布扣

再次写入,只剩下一个字节可写, limit在调用 flip() 时被设置为 5,并且 position 不能超过 limit。所以最后一次写入操作从缓冲区取出一个字节并将它写入输出通道。这使得 position 增加到 5,并保持 limit 不变。

 bubuko.com,布布扣

  • clear

它将limit设置为与capacity 相同;它设置 position为0;可以再次往缓冲区写数据了。

 bubuko.com,布布扣

缓冲区操作

  • 分配
  • bubuko.com,布布扣
    /**
         * 分配缓冲区
         */
        @Test
        public void allocateBuffer(){
            ByteBuffer bf=ByteBuffer.allocate(1024);
            System.out.println("position:"+bf.position());
            System.out.println("limit:"+bf.limit());
            System.out.println("capacity:"+bf.capacity());
        }
    bubuko.com,布布扣

    运行结果:

    bubuko.com,布布扣

  • 包装
  • bubuko.com,布布扣
    /**
         * 将原有数组包装成一个缓冲区。
         */
        public void wrapBuffer(){
            int [] ints={1,2,3,4,5};
            IntBuffer ib=IntBuffer.wrap(ints);
            ib.put(1,8);
            System.out.println(Arrays.toString(ints));
        }
    bubuko.com,布布扣

    运行结果:

          bubuko.com,布布扣

     数组和缓冲区共用一分数据。

  • 分片
  • bubuko.com,布布扣
    @Test
        public void sliceBuffer() {
            IntBuffer ib = IntBuffer.allocate(10);
            for(int i=0;i<10;i++){
                ib.put(i);
            }
            ib.position(3);
            ib.limit(6);
            IntBuffer sliceBuf=ib.slice();
            System.out.println("before slice:"+Arrays.toString(sliceBuf.array()));
            for(int j=0;j<sliceBuf.capacity();j++){
                sliceBuf.put(j,sliceBuf.get()*3);
            }
            System.out.println("after slice:"+Arrays.toString(sliceBuf.array()));
            System.out.println("old buffer"+Arrays.toString(sliceBuf.array()));
        }
    bubuko.com,布布扣

    运行结果:

          bubuko.com,布布扣

       原缓冲区和新的缓冲区分片共享同一个底层数据数组,并且对缓冲区分片的新缓冲区修改只影响子缓冲区。

  • 压缩
  • bubuko.com,布布扣
    @Test
         public void compactBuffer() {
            CharBuffer cb = CharBuffer.allocate(15);
            for (int i = 65; i < 75; i++) {
                cb.put((char) i);
            }
            cb.flip();
            System.out.println("original buffer:"+Arrays.toString(cb.array()));
            System.out.println("original positon:"+cb.position());
            System.out.println("original limit:"+cb.limit());
            for(int j=0;j<6;j++){
                cb.get();
            }
            System.out.println("after get position:"+cb.position());
            cb.compact();
            System.out.println("after compact position:"+cb.position());
            System.out.println("after compact limit:"+cb.limit());
            System.out.println("after compact buffer:"+Arrays.toString(cb.array()));
            cb.flip();
            System.out.println("after flip position:"+cb.position());
            System.out.println("after flip limit:"+cb.limit());
        }
    bubuko.com,布布扣

    运行结果:

        bubuko.com,布布扣

        未读的元素移动到下表0开始,position为最后一个未读元素的下一个下标,limit在这个过程中没变化,如果想读取这部分元素,执行一次翻转。

  • 比较

  两个缓冲区相等的充分必要条件:

  1. 两个缓冲区类型必须相同
  2. 两个缓冲区剩余元素数量必须相同,两个缓冲区容量可以不同

  3.  两个缓冲区通过get()取得的元素序列必须相同

bubuko.com,布布扣
@Test
    public void compareBuffer(){
        //cb1和cb2的capacity不相等
        CharBuffer cb1=CharBuffer.allocate(10);
        CharBuffer cb2=CharBuffer.allocate(8);
        for (int i=65;i<75;i++){
            cb1.put((char)i);
        }
        for (int j=69;j<75;j++){
            cb2.put((char)j);
        }
        cb1.flip();
        cb2.flip();
        System.out.println("original cb1:"+Arrays.toString(cb1.array()));
        System.out.println("original cb2:"+Arrays.toString(cb2.array()));
        //cb1读取六个元素
        for(int m=0;m<5;m++){
           cb1.get();
        }
        //cb2读取一个元素
        cb2.get();
        System.out.println(cb1.equals(cb2));
    }
bubuko.com,布布扣

     运行结果:

       bubuko.com,布布扣

只读缓冲区

  • bubuko.com,布布扣
    public void readOnlyBuffer() {
            IntBuffer ib = IntBuffer.allocate(10);
            for (int i = 0; i < 10; i++) {
                ib.put(i);
            }
            System.out.println("original buffer:"+Arrays.toString(ib.array()));
            IntBuffer readOnlyBuffer=ib.asReadOnlyBuffer();
            readOnlyBuffer.flip();
            //以下语句会接收异常:ReadOnlyBufferException。
            //System.out.println("readonly buffer:"+Arrays.toString(readOnlyBuffer.array()));
            System.out.print("original readonly buffer:");
            for (int j=0;j<readOnlyBuffer.capacity();j++){
                System.out.print(readOnlyBuffer.get());
    
            }
        }
    bubuko.com,布布扣

    只读缓冲区会和原缓冲区公用一分数据。

直接缓冲区

    给定一个直接字节缓冲区,Java 虚拟机将尽最大努力直接对它执行本机 I/O 操作。也就是说,它会在每一次调用底层操作系统的本机 I/O 操作之前(或之后),尝试避免将缓冲区的内容拷贝到一个中间缓冲区中(或者从一个中间缓冲区中拷贝数据)

bubuko.com,布布扣
/**
     * 直接缓冲区
     * @throws Exception
     */
    @Test
    public void directBuffer() throws Exception {
        FileInputStream fi = new FileInputStream(this.sourcePath);
        FileOutputStream fo = new FileOutputStream(this.destPath);
        ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);
        FileChannel fic = fi.getChannel();
        FileChannel foc = fo.getChannel();
        while (fic.read(directBuffer) != -1) {
            directBuffer.flip();
            foc.write(directBuffer);
            directBuffer.clear();
        }
        fi.close();
        fo.close();
    }
bubuko.com,布布扣

内存映像

     内存映射文件 I/O 是通过使文件中的数据出现为内存数组的内容来完成的。一般来说,只有文件中实际读取或者写入的部分才会送入(或者 映射 )到内存中。

只能通过FileChannel来创建。

    代码实例:

bubuko.com,布布扣
public void mappedByteBuffer() throws  Exception{
        FileInputStream fi = new FileInputStream(this.sourcePath);
        //MappedByteBuffer是ByteBuffer的子类。
        MappedByteBuffer mappedByteBuffer=fi.getChannel().map(FileChannel.MapMode.READ_ONLY,0l,1024l);

    }
bubuko.com,布布扣

字节缓冲区

  • 字节顺序
  1. 大端字节

        bubuko.com,布布扣

       2.  小端字节

          bubuko.com,布布扣

  • 取决于硬件设计,JVM默认是大端字节,IP协议使用大端的网络字节顺序。
  • JVM对字节顺序的支持:ByteOrder

         获取本地字节顺序:ByteOrder.nativeOrder();

    

bubuko.com,布布扣
 /**
     * 字节顺序
     */
    @Test
    public void byteOrder(){
        System.out.println("My mac pro byte order:"+ByteOrder.nativeOrder());
    }
bubuko.com,布布扣

        运行结果:

        bubuko.com,布布扣

     

视图缓冲区

     

bubuko.com,布布扣
/**
     * 视图buffer
     */
    @Test
    public void viewBuffer() {
        this.byteOrder();
        ByteBuffer bb = ByteBuffer.allocate(16).order(ByteOrder.BIG_ENDIAN);
        CharBuffer cb=bb.asCharBuffer();
        bb.put((byte)0);
        bb.put((byte)‘r‘);
        bb.put((byte)0);
        bb.put((byte)‘e‘);
        bb.put((byte)0);
        bb.put((byte)‘q‘);
        bb.put((byte)0);
        bb.put((byte)‘u‘);
        bb.put((byte)0);
        bb.put((byte)‘e‘);
        bb.put((byte)0);
        bb.put((byte)‘l‘);
        bb.put((byte)0);
        bb.put((byte)‘q‘);
        bb.put((byte)0);
        bb.put((byte)‘i‘);
        System.out.println("original bb position:"+bb.position()+",limit:"+bb.limit()+",bb is:"+Arrays.toString(bb.array()));
        System.out.println("view buffer cb position:"+cb.position()+",limit:"+cb.limit()+",bb is:"+cb.toString());
    }
bubuko.com,布布扣

     运行结果:

    bubuko.com,布布扣

NIO之Buffer,布布扣,bubuko.com

NIO之Buffer

原文:http://www.cnblogs.com/requelqi/p/3701787.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!