冷文学习者

文章 分类 标签
22 7 36

公告

冷文博客(KEVINLU98.COM),记录我日常业余的一点一滴。
利用业余时间写与typecho与emlog的主题、插件等,同时也分享一些资源与技术帖
顺带帮大家免费代下载IT教程吧的资源 传送门

NIO中Buffer的基本原理

MR丶冷文 2021-04-29 50 0条评论 技术学习 学习缓冲区bufferjavanio

首页 / 正文

Buffer的基本原理

我们说的缓冲区本质上是一个数组,但它其实是一个特殊的数组,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如果我们使用get()方法从缓冲区获取数据或者使用put()方法把数据写入缓冲区,都会引起缓冲区状态变化。

在缓冲区中,最重要的属性有下面三个,它们一起合作完成对缓冲区内部的变化跟踪

  • position:指定下一个将要写入或者读取的元素索引,它的值由get()/put()方法自动更新,在新创建一个Buffer对象时,position被初始化为0
  • limit:指定还有多少数据需要取出(在从缓冲区写入通道时),或者还有多少空间可以放入数据(在从通道读入缓冲区时)
  • capacity:指定了可以存储在缓冲区中的最大数据容量,实际上,它指定了底层数组的大小,或者至少是指定了准许我们使用的底层数组的容量

这三个属性之间有一些相对大小的关系:0<=position<=limit<=capacity。

举例说明

我们现在需要取读磁盘的一个文件,文件内容如下:

lengwen

我们创建一个新的容量大小为10的ByteBuffer对象,在初始化时将position设置为0,limit和capacity设置为10,在以后使用ByteBuffer对象的过程中,capacity的值不在变化,而其他两个将会随着使用而变化。

https://imagebed-1252410096.cos.ap-nanjing.myqcloud.com/20210429/63ea1f29477e4dd3a7e1916c774f8945.png

我们现在要读文件,对于缓冲区来说,是将数据从inputstream的通道中写到缓冲区, 可以看出我们文件中数据的长度为7,此时往缓冲区写完后position的值为7,即下一个将要被写入的字节索引为7.而limit仍为10

https://imagebed-1252410096.cos.ap-nanjing.myqcloud.com/20210429/23b6f089da22442d9c72cd4c6b5580e0.png

下一步是将数据写入到输出的通道,对于缓冲区来说,就是从缓冲区中读取数据,但在些之前,必须调用flip()方法。该方法将会完成以下两件事情:(1)把limit设置为当前的position值;(2)把position设置为0

解释:由于position被设置为0,所以可以保证在下一步输出时读取的是缓冲区的第一个字节,而limit被设置为当前的position,可以保证读取的数据正好是之前写入缓冲区的数据

https://imagebed-1252410096.cos.ap-nanjing.myqcloud.com/20210429/89ac67ec210040519684e941ad8be487.png

现在调用git()方法从缓冲区中读取数据写入输出通道,这会导致position的增加而limit保持不变,但position不会超过linit的值,所以在读取之前写入缓冲区的7字节之后,position和limit的值都为7

https://imagebed-1252410096.cos.ap-nanjing.myqcloud.com/20210429/9d7f48759a9c40e089b504c204745801.png

在从缓冲区读取完成之后,limit的值仍然为7,此时调用clear()方法能够把所有的状态变化设置为初始化时的值

https://imagebed-1252410096.cos.ap-nanjing.myqcloud.com/20210429/63ea1f29477e4dd3a7e1916c774f8945.png

举例代码

上面说明了使用缓冲区读取文件的全过程,现在去实现一下上述过程

package cn.kevinlu98.netty.buffer;

import java.io.FileInputStream;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * Author: 鲁恺文
 * Date: 2021/4/29 3:48 下午
 * Email: lukaiwen@xiaomi.com
 * Description:
 */
public class BufferReadFile {
    public static void main(String[] args) throws IOException {
        //这里用的是文件I/O处理
        FileInputStream fis = new FileInputStream("/Users/lengwen/Desktop/buffer.txt");
        //创建文件的操作管道
        FileChannel channel = fis.getChannel();
        //分配一个10大小的缓冲区,其实就是分配一个10个大小的Byte数组
        ByteBuffer buffer = ByteBuffer.allocate(10);
        printInfo("初始化", buffer);
        //将数据从通道中写到缓冲区
        channel.read(buffer);
        printInfo("调用read", buffer);
        //把limit设置为当前的position值;把position设置为0
        buffer.flip();
        printInfo("调用flip", buffer);
        while (buffer.remaining() > 0) {
            byte b = buffer.get();
            System.out.print((char) b);
        }
        printInfo("调用完get", buffer);
        //调用clear恢复position limit

        buffer.clear();
        printInfo("调用clear", buffer);

        fis.close();
    }

    private static void printInfo(String step, ByteBuffer buffer) {
        System.out.println();
        System.out.println("step:"+step);
        System.out.println("\tcapacity:" + buffer.capacity());
        System.out.println("\tposition:" + buffer.position());
        System.out.println("\tlimit:" + buffer.limit());
    }
}

运行结果

step:初始化
    capacity:10
    position:0
    limit:10

step:调用read
    capacity:10
    position:7
    limit:10

step:调用flip
    capacity:10
    position:0
    limit:7
lengwen
step:调用完get
    capacity:10
    position:7
    limit:7

step:调用clear
    capacity:10
    position:0
    limit:10

评论(0)

当前没有评论,还不快来留下第一个脚印吧

热门文章

最新评论

  • 难说博客

    那就回复看看

  • 他听

    给大佬递杯卡布奇诺[捂嘴笑]

  • 我愿提笔画尽天下

    向大佬低头[太开心]

  • flvck

    @MR丶冷文 [[呲牙]]可能看错了,不是这个

  • MR丶冷文

    @flvck ?? 这个主题应该还没发布呢[委屈]

日历

2021年05月

      1
2345678
9101112131415
16171819202122
23242526272829
3031     

文章目录

推荐关键字: IO模型 缓冲区 buffer java nio

上一张 下一张