NIO之Buffer

缓冲区(Buffer)

  • 缓冲区(Buffer) ):一个用于特定基本数据类型的容器。由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类。
  • Java NIO 中的 Buffer 主要用于与 NIO 通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的。

缓冲区类型(Buffer)

在Java NIO中负责数据的存取。缓冲区就是数组。用于存储不同数据类型的数据。
根据数据类型的不同(boolean除外),提供了相应类型的缓冲区

  1. ByteBuffer
  2. CharBuffer
  3. ShortBuffer
  4. IntBuffer
  5. LongBuffer
  6. FloatBuffer
  7. DoubleBuffer
    上述缓冲区的管理方式几乎一致,通过allocate获取缓冲区

缓冲区存取数据的两个核心方法

  • put() : 存入数据到缓冲区中
    put(byte b):将给定单个字节写入缓冲区的当前位置
    put(byte[] src):将 src 中的字节写入缓冲区的当前位置
    put(int index, byte b):将指定字节写入缓冲区的索引位置(不会移动 position)
  • get() : 获取缓冲区的数据
    get() :读取单个字节
    get(byte[] dst):批量读取多个字节到 dst 中
    get(int index):读取指定索引位置的字节(不会移动 position)

缓冲区的四个核心属性

  • capacity : 容量,标识缓冲区中最大存储数据的容量,一旦声明不能改变。
  • limit : 界限,标识缓冲区中可以操作数据的大小。(limit后的数据不能进行读写 )
  • position : 位置,标识缓冲区中正在操作数据的位置。
  • mark : 标记,表示记录当前position的位置。可以通过reset()恢复到mark的位置。
    在这里插入图片描述

Buffer 的常用方法

方 方描 描
Buffer clear()清空缓冲区并返回对缓冲区的引用
Buffer flip()将缓冲区的界限设置为当前位置,并将当前位置重置为 0 ,切换读写模式
int capacity()返回 Buffer 的 capacity 大小
boolean hasRemaining()判断缓冲区中是否还有元素
int limit()返回 Buffer 的界限(limit) 的位置
Buffer limit(int n)将设置缓冲区界限为 n, 并返回一个具有新 limit 的缓冲区对象
Buffer mark()对缓冲区设置标记
int position()返回缓冲区的当前位置 position
Buffer position(int n)将设置缓冲区的当前位置为 n , 并返回修改后的 Buffer 对象
int remaining()返回 position 和 limit 之间的元素个数
Buffer reset()将位置 position 转到以前设置的 mark 所在的位置
Buffer rewind()将位置设为为 0, 取消设置的 mark

直接缓冲区与非直接缓冲区

非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在 JVM 的内存中
直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率

  • 字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在
    机 此缓冲区上执行本机 I/O 操作。也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),
    虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。
  • 直接字节缓冲区可以通过调用此类的 allocateDirect() 工厂方法 来创建。此方法返回的 缓冲区进行分配和取消
    分配所需成本通常高于非直接缓冲区 。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对
    应用程序的内存需求量造成的影响可能并不明显。所以,建议将直接缓冲区主要分配给那些易受基础系统的
    机 本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好
    处时分配它们。
  • 直接字节缓冲区还可以过 通过FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建 。该方法返回
    MappedByteBuffer 。Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。如果以上这些缓冲区
    中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,并且将会在
    访问期间或稍后的某个时间导致抛出不确定的异常。
  • 字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect() 方法来确定。提供此方法是为了能够在
    性能关键型代码中执行显式缓冲区管理

在这里插入图片描述
在这里插入图片描述

实例代码

public class TestBuffer1 {
    @Test
    public void test1(){
        String str = "abcde";

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        System.out.println("--------------------allocate()----------------");
        // 1. 分配一个指定大小的缓冲区
        System.out.println("position==" + byteBuffer.position());
        System.out.println("limit==" + byteBuffer.limit());
        System.out.println("capacity==" + byteBuffer.capacity());

        System.out.println("--------------------put()----------------");
        // 2. 利用 put() 存入数据到缓冲区中
        byteBuffer.put(str.getBytes());
        System.out.println("position==" + byteBuffer.position());
        System.out.println("limit==" + byteBuffer.limit());
        System.out.println("capacity==" + byteBuffer.capacity());

        System.out.println("--------------------flip()----------------");
        // 3. 切换读取数据模式
        byteBuffer.flip();
        System.out.println("position==" + byteBuffer.position());
        System.out.println("limit==" + byteBuffer.limit());
        System.out.println("capacity==" + byteBuffer.capacity());

        System.out.println("--------------------get()----------------");
        // 4. 利用 get() 读取缓冲区中的数据
        byte[] dst = new byte[byteBuffer.limit()];
        byteBuffer.get(dst);
        System.out.println("取到的数据==" + new String(dst, 0, dst.length));
        System.out.println("position==" + byteBuffer.position());
        System.out.println("limit==" + byteBuffer.limit());
        System.out.println("capacity==" + byteBuffer.capacity());

        System.out.println("--------------------rewind()----------------");
        // 5. rewind() : 可重复读
        byteBuffer.rewind();
        System.out.println("position==" + byteBuffer.position());
        System.out.println("limit==" + byteBuffer.limit());
        System.out.println("capacity==" + byteBuffer.capacity());


        System.out.println("--------------------clear()----------------");
        // 6. clear() : 清空缓冲区. 但是缓冲区中的数据依然存在,但是处于“被遗忘”状态
        byteBuffer.clear();
        //byte[] dst1 = new byte[5];
        //byteBuffer.get(dst1);
        //System.out.println("虽然清空了缓冲区,数据依然可以获取到==" + new String(dst1));
        System.out.println("position==" + byteBuffer.position());
        System.out.println("limit==" + byteBuffer.limit());
        System.out.println("capacity==" + byteBuffer.capacity());

    }

    @Test
    public void test2(){
        String str = "abcde";
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        byteBuffer.put(str.getBytes());

        // 切换到读取模式
        byteBuffer.flip();

        // 读取数据
        byte[] dst = new byte[byteBuffer.limit()];
        byteBuffer.get(dst, 0, 2);
        System.out.println("读取到的数据为" + new String(dst, 0, dst.length));
        System.out.println("position==" + byteBuffer.position());
        System.out.println("limit==" + byteBuffer.limit());
        System.out.println("capacity==" + byteBuffer.capacity());

        // 判断缓冲区中是否还有剩余数据
        if (byteBuffer.hasRemaining()){
            // 获取缓冲区中可以操作的数量
            System.out.println("" + byteBuffer.remaining());
        }
    }

    @Test
    public void test3(){
        //分配直接缓冲区
        ByteBuffer buf = ByteBuffer.allocateDirect(1024);

        System.out.println("当前缓冲区是否为直接缓冲区"+buf.isDirect());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值