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();
}
相关推荐
快意咖啡~2 天前
java.nio.charset.MalformedInputException: Input length = 1
java·开发语言·nio
·云扬·2 天前
Java IO 与 BIO、NIO、AIO 详解
java·开发语言·笔记·学习·nio·1024程序员节
西京刀客5 天前
BIO、NIO、AIO的区别?
netty·nio·bio
java小吕布6 天前
Java NIO 深度解析:构建高效的 I/O 操作
java·开发语言·nio
秋恬意6 天前
Java NIO 核心知识总结
java·开发语言·nio
XiaoLiuLB10 天前
Docker 指令详解:全面掌握容器化管理工具
java·tomcat·nio
XiaoLiuLB11 天前
Tomcat NIO 配置实操指南
java·tomcat·nio
鱼跃鹰飞14 天前
大厂面试真题-说说同步IO异步IO以及BIO、NIO、AIO
java·面试·nio
木小同15 天前
JAVA基础之NIO
面试·java基础·nio
wainyz15 天前
Java NIO操作
java·开发语言·nio