NIO之ByteBuffer

NIO中的ByteBuffer是缓冲区,其中有几个比较重要的属性capacity,position和limit。

capacity:

其中,capacity是缓冲区的容量大小,在分配内存空间后不会改变。

limit:

limit是限制位置,在读写模式切换后limit的位置也跟着切换,切换到读限制位置和写限制位置。在写模式下limit一般位于capacity处,即不超出buffer的范围即可。在读模式下limit一般位于buffer中最后一个字符的位置,即在读的时候不超出存有内容的范围即可。

position:

position是写入位置或读取位置,在读写切换时也会随之切换。如写模式下随着字符的写入,position的位置会相应地后移,当切换为读模式时,position会一直最前方,此时其代表读取位置。读取操作结束后在切回写模式时,分为两种情况。第一种是使用clear进行切换,之前缓冲区里的全部元素,无论切换前是否读过,都直接抛弃,position移至buffer的最前方。另一种是compact,这种方式是保留没读过的元素,也就是读模式的position和读模式的limit之间的元素,切换写模式时会被保留,position会指向被保留元素的下一个。

如下列的一些图

一开始:

写入4字节:

flip切换为读模式,position切换到读取位置(最前方),limit切换为读取限制,有元素的最后一个位置:

读了4个字节后:

以clear切换为写模式,元素清空,limit和position也进行切换:

假设只读了两个字节,剩下的两个没读,并且是以compact方式进行的切换,那会保留没读过的元素,position和limit也切换为写模式,并且position位于保留元素的后方:

关于position还有需要注意的是, 我们在读模式下进行读取时,一般是调用buffer的get方法,这时每读一个字符指针就会后移一位。注意可以调用 rewind 方法将 position 重新置为 0,或者调用 get(int i) 方法获取索引 i 的内容,它不会移动读指针。另外,使用mark 可以在读取时做一个标记,即使 position 改变,只要调用 reset 就能回到 mark 的位置,但是需注意rewind 和 flip 都会清除 mark 位置。

实战举例,解决网络收发数据时的半包粘包情况,灵活利用了ByteBuffer读写模式的切换以及对于position的灵活应用:

java 复制代码
public static void main(String[] args) {
    ByteBuffer source = ByteBuffer.allocate(32);
    //                     11            24
    source.put("Hello,world\nI'm zhangsan\nHo".getBytes());
    split(source);

    source.put("w are you?\nhaha!\n".getBytes());
    split(source);
}

private static void split(ByteBuffer source) {
    // 切换为读模式
    source.flip();
    // buffer中容量的总大小
    int oldLimit = source.limit();
    for (int i = 0; i < oldLimit; i++) {
        // 使用source.get(i)的模式,读取位置position并不会后移
        if (source.get(i) == '\n') {
            System.out.println(i);
            // 当前位置与position间的长度是新字符串长度,position是上一个串的结尾
            ByteBuffer target = ByteBuffer.allocate(i + 1 - source.position());
            // 0 ~ limit
            source.limit(i + 1);
            // 从source 读,向 target 写,position后移到该完整串的结尾
            target.put(source); 
            debugAll(target);
            source.limit(oldLimit);
        }
    }
    // 有剩余的半包并未真正读取,切换写模式时保留,等后续内容到达补全
    source.compact();
}
相关推荐
yzp-2 天前
Java NIO Reactor 模式
java·开发语言·nio
babywew13 天前
基于粒子群算法的MPPT在阴影变换及负载变化下的实现
nio
程序媛青青3 天前
Java 中 NIO 和IO 的区别
java·开发语言·nio
zwxu_4 天前
Nginx NIO对比Java NIO
java·nginx·nio
爬山算法6 天前
Netty(5)Netty的ByteBuf是什么?它与Java NIO的ByteBuffer有何不同?
java·开发语言·nio
SoleMotive.6 天前
bio、nio、aio的区别以及使用场景
python·算法·nio
whltaoin10 天前
【Java SE】Java IO 类常用方法大全:从字节流到 NIO 的核心 API 汇总
java·开发语言·api·nio
whltaoin11 天前
【Java SE】Java IO体系深度剖析:从原理到实战的全方位讲解(包含流操作、序列化与 NIO 优化技巧)
java·开发语言·nio·se·io体系
阿杰同学14 天前
Java NIO 面试题及答案整理,最新面试题
java·开发语言·nio
TracyCoder12316 天前
大白话讲Java NIO
java·开发语言·nio