4、Buffer

    4、Buffer

        缓冲区实际上是一个容器,一个连续数组。在Java NIO中负责数据的存储,用于存储不同数据类型的数据。Buffer是一个抽象类。

        (1)、子类

            根据数据类型不同(boolean除外),提供了相应类型的缓冲区。以下缓冲区的管理方式几乎一致,通过allocate()方法获取非直接缓冲区,但ByteBuffer也可以通过allocateDirect()分配直接缓冲区。

            ①、ByteBuffer:存储字节数据到缓冲区

            ②、CharBuffer:存储字符数据到缓冲区

            ③、ShortBuffer

            ④、IntBuffer

            ⑤、FloatBuffer

            ⑥、LongBuffer

            ⑦、DoubleBuffer

            这几个子类分别对应各自基本数据类型:byte、char、short、int、float、long、double。

        (2)、Buffer抽象类

            ①、属性

                a、capacity:容量,即可以容纳的最大数据量;在缓冲区创建时被设定且不能改变

                b、position:位置,下一个要被读或写的元素的索引,每次读写缓冲区数据时都会改变该值,为下次读写作准备

                c、limit:表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作(limit后的数据不能进行读写)

                d、mark:标记,调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置

package java.nio;
public abstract class Buffer {
    /**
     * 0 <= mark <= position <= limit <= capacity
     */
    // 容量,即可以容纳的最大数据量;在缓冲区创建时被设定且不能改变
    private int capacity;
    // 位置,下一个要被读或写的元素的索引,每次读写缓冲区数据时都会改变该值,为下次读写作准备
    private int position = 0;
    // 表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作(limit后的数据不能进行读写)。
    private int limit;
    // 标记,调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置
    private int mark = -1;
    /**
     * 在此缓冲区的位置设置标记
     */
    public final Buffer mark() {
        mark = position;
        return this;
    }
    /**
     * 将此缓冲区的位置重置为以前标记的位置
     */
    public final Buffer reset() {
        int m = mark;
        if (m < 0)
            throw new InvalidMarkException();
        position = m;
        return this;
    }
    /**
     * 清楚此缓冲区,即将各个标记恢复到初始状态,但是数据并没有真正擦除
     */
    public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }
    /**
     * 反转此缓冲区(read、write)
     */
    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }
    /**
     * 重绕此缓冲区
     */
    public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }
    /**
     * 返回当前位置与限制之间的元素数
     */
    public final int remaining() {
        return limit - position;
    }
    /**
     * 告知在当前位置和限制之间是否有元素
     */
    public final boolean hasRemaining() {
        return position < limit;
    }
    /**
     * 告知此缓冲区是否为只读缓冲区
     */
    public abstract boolean isReadOnly();
    /**
     * 告知此缓冲区是否具有可访问的底层实现数组
     * @since 1.6
     */
    public abstract boolean hasArray();
    /**
     * 返回此缓冲区的底层实现数组
     * @since 1.6
     */
    public abstract Object array();
    /**
     * 返回此缓冲区的底层实现数组中第一个缓冲区元素的偏移量
     * @since 1.6
     */
    public abstract int arrayOffset();
    /**
     * 告知此缓冲区是否为直接缓冲区
     * @since 1.6
     */
    public abstract boolean isDirect();
}

        (3)、ByteBuffer抽象类

package java.nio;
public abstract class ByteBuffer extends Buffer implements Comparable<java.nio.ByteBuffer>
{
    /**
     * 从堆空间中分配一个容量大小为capacity的byte数组作为缓冲区的byte数据存储器
     */
    public static ByteBuffer allocate(int capacity) {
        if (capacity < 0)
            throw new IllegalArgumentException();
        // 在堆中创建缓冲区,在JVM内存中。
        return new HeapByteBuffer(capacity, capacity);
    }
    /**
     * 不使用JVM堆栈而是直接通过操作系统来创建内存块用作缓冲区,它与当前操作系统能够更好的耦合,因此能进一步提高I/O操作速度。
     * 但是分配直接缓冲区的系统开销很大,因此只有在缓冲区较大并长期存在,或者需要经常重用时,才使用这种缓冲区。
     */
    public static ByteBuffer allocateDirect(int capacity) {
        // 在物理内存中建立缓冲区,不在JVM中,通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用来进行操作。
        return new DirectByteBuffer(capacity);
    }
}

            ①、put(byte b)

                相对写,向position的位置写入一个byte,并将postion+1,为下次读写作准备。

            ②、put(int index, byte b)

                绝对写,向byteBuffer底层的bytes中下标为index的位置插入byte b,不改变position。

            ③、Buffer => flip()

                将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态。

            ④、byte get()

                相对读,从position位置读取一个byte,并将position+1,为下次读写作准备。

            ⑤、byte get(int index)

                绝对读,读取byteBuffer底层的bytes中下标为index的byte,不改变position。

            ⑥、Buffer => rewind()

                把position设为0,mark设为-1,不改变limit的值。

            ⑦、Buffer => clear()

                把position = 0;limit = capacity;mark = -1;  但是并不影响底层byte数组的内容,缓冲区的数据依然存在。

            ⑧、Buffer => mark()

                把mark设置成position的值,标记position当前的位置。

            ⑨、Buffer => reset()

                把position设置成mark的值,相当于之前做过一个标记,现在要退回到之前标记的地方。

        (4)、直接缓冲区与非直接缓冲区

//非直接缓冲区:堆内创建缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
//直接缓冲区:JVM内存外,直接在物理内存创建缓冲区,通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用来进行操作。
ByteBuffer direct = ByteBuffer.allocateDirect(1024);

            ①、直接字节缓冲区可以通过调用此类的allocateDirect()方法来创建,通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用来进行操作。此方法返回的缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因为对应用程序的内存需求量造成影响并不明显。所以建议将直接缓冲区主要分配给那些易受基础系统的本级IO操作影响的大型、持久的缓冲区。

            ②、字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其isDirect()方法来确定,提供此方法是为了能够在性能关键型代码中执行显示缓冲区管理。

        (5)、分散和聚集

            NIO还支持通过多个Buffer(即 Buffer数组)完成读写操作,即Scattering和Gathering

            ①、Scattering(分散):将数据写入到buffer时,可以采用buffer数组,依次写入。

            ②、Gathering(聚集):从buffer读取数据时,可以采用buffer数组,依次读。

v4l2_buffer 是一个在 Linux 内核中使用的结构体,用于描述视频缓冲区的信息。V4L2(Video for Linux 2)是一个用于视频设备的内核接口。 该结构体的定义如下: ```c struct v4l2_buffer { __u32 index; // 缓冲区索引号 __u32 type; // 缓冲区所属的数据流类型 __u32 bytesused; // 已使用的字节数 __u32 flags; // 缓冲区状态标志 struct timeval timestamp; // 缓冲区时间戳 struct v4l2_timecode timecode; // 缓冲区时间码 __u32 sequence; // 缓冲区序列号 __u32 memory; // 缓冲区所在的内存类型 union { __u32 offset; // 缓冲区在内存中的偏移量 unsigned long userptr; // 用户空间缓冲区指针 struct v4l2_plane *planes; // 多平面缓冲区的指针 int fd; // 文件描述符 } m; __u32 length; // 缓冲区的长度(字节数) __u32 field; // 采集或输出的场序号 __u32 sequence; // 当前帧的序列号 }; ``` 通过使用 v4l2_buffer 结构体,可以获取视频缓冲区的相关信息,比如缓冲区索引号、已使用的字节数、缓冲区状态标志、时间戳等。根据不同的使用场景,可以通过设置结构体的字段来传递参数给视频设备驱动程序,并获取视频数据。 v4l2_buffer 结构体中的 memory 字段指示了缓冲区所在的内存类型,可以是 V4L2_MEMORY_MMAP(使用 mmap 映射到用户空间)、V4L2_MEMORY_USERPTR(用户空间缓冲区指针)或 V4L2_MEMORY_DMABUF(DMA 缓冲区)等。 希望以上信息能够帮助到你!如果还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值