`
longzhun
  • 浏览: 371690 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

字节缓冲区ByteBuffer

    博客分类:
  • NIO
 
阅读更多
ByteBuffer其实就是一个字节缓冲区, 在这里你可以对缓冲区的数据进行 字节级的操作. 这样的好处在于你可以比较方便的获取到底层的字节操作和字节数据. 比如你有一个int型数据, 而你想获取他的byte[]数组, 你可以这样做:
ByteBuffer buffer = ByteBuffer.allocate(1024); //分配一定的空间,1024
int i = 90;
buffer.putInt(i);
byte[] array = buffer.array(); //获取该buffer的数组,这个数组是跟该buffer一一对应的
for(int j =0; j <4;j++){
System.out.println(Integer.toBinaryString(array[j] & 0xFF));
}
public static ByteBuffer wrap(byte[] array)
将array中的数据包装到ByteBuffer中
byte[] array = new byte[1024];
ByteBuffer buffer = ByteBuffer.wrap(array);

等效于
ByteBuffer buffer = ByteBuffer.allocate(1024); //分配一定的空间,1024

flip
public final Buffer flip()
反转此缓冲区。首先对当前位置设置限制,然后将该位置设置为零。如果已定义了标记,则丢弃该标记。
当将数据从一个地方传输到另一个地方时,经常将此方法与 compact 方法一起使用。

我最终的理解是: 文档翻译得太差了, 把不应该翻译的内容也译成了中文, 所以反而不容易理解.
关键就在以下 2 处:

当前位置: 这个可以直观地理解为缓冲区中的当前数据指针, 或是 SQL 中的游标, 记为 curPointer.
限制: 这个可以理解成实际操作的缓冲区段的结束标记, 记为 endPointer.
反转: 这个完全是对 flip 这个词不负责的翻译, 如果参照 DirectX 里的 flip() 而译为翻转/翻页, 那就好理解得多, 就像写信/看信, 写/看完一页后, 翻到下一页, 眼睛/笔从页底重新移回页首.
这个翻转背后的操作其实就是 "把 endPointer 定位到 curPointer 处, 并把 curPointer 设为 0".

关于标记, 在这里不涉及. 下一句说到常与 compact 方法一起使用, 是可以想像的, 因为 compact 方法对数据进
行了压缩, 有效数据的真实长度发生了变化, 肯定需要用 flip 重新定位结束标记.

在填充, 压缩等数据操作时, curPointer 估计都是自动更新了位置的, 总是指向最后一个有效数据, 所以每次调
用 flip() 后, endPointer 就指向了有效数据的结尾, 而 curPointer 指向了 0 (缓冲起始处).

举个图例:
(c 和 e 分别代表 curPointer 和 endPointer 两个指针)

* 先是一个空的 ByteBuffer (大小为 10 字节)
-------------------
-------------------
c
e


* 然后填充 5 字节数据
-------------------
0 1 2 3 4
-------------------
e         c
此时, endPointer 尚在 0 处, curPointer 移到了数据结尾.
经测试, 此时若取数据, 将得到 5 个字节, 内容通常为 0 (也有可能是未知), 因为实际上取到的是从 c 处到缓冲
区实际结束处的 5 个未初始化的字节.

调用一次 flip() 后
-------------------
0 1 2 3 4
-------------------
c         e
此时, endPointer 先被移到 curPointer, 然后 curPointer 移到 0.
通过测试可见, ByteBuffer 取数据时, 是从 curPointer 起, 到 endPointer 止, 若 curPointer > endPointer, 则取到缓冲区结束.

flip() 即有两个作用, 一是将 curPointer 移到 0, 二是将 endPointer 移到有效数据结尾.

此行可由以下两行代替:
buff.limit( buff.position());
buff.position( 0 );

可见对其工作原理的理解, 应该是正确的
 总结
1. put 数据时, 不会自动清除缓冲区中现有的数据.
2. 每一次 get 或 put 后, curPointer 都将向缓冲区尾部移动, 移动量=操作的数据量.
3. get/put 均是从 curPointer 起, 到 curPointer + 操作的数据长度止.
4. get/put 操作中, 若 curPointer 超过了 endPointer 或缓冲区总长度, 将抛出 java.nio.BufferUnderflowException 异常.

注: curPointer 和 endPointer 只是为文中方便描述命名的, 实际分别对应到 ByteBuffer.position() 和 ByteBuffer.limit() 两个方法
关于flip
ByteBuffer 的filp函数, 将缓冲区的终止位置limit设置为当前位置, 缓冲区的游标position(当前位置)重设为0.
比如 我们有初始化一个ByteBuffer 后有
ByteBuffer buffer = ByteBuffer.allocate(1024);
这是 终止位置limit在1024, 而起始位置position在 0
如果我们添加一个数据,
buffer.putint(90);
这会使起始位置 position 移到4, 也就是说postion始终都在第一个可写字节的位置上. limit 则不会发生改变
而如果这时,我们调用
buffer.flip();
position转到0, limit转到 4 也就是原来的position 所在位置
这里的flip, 从另外一个角度上来说, 是在读数据时,操作的
然而, 如果我此时在写
buffer.putInt(90);
就会将原来的覆盖掉
如果我们在写, 这时就不行了, 就会重现问题了. 因为我们的limit是4, 我们写入数据不能超过这个limit,(当然还有capacity)
所以在写的时候,最好先清空buffer.clear();
如果真的不想清空, 也可以调用
buffer.limit(newlimit);
设置一个较大的limit, 再写入
当然不能超过capacity, 可以等于 capacity
分享到:
评论

相关推荐

    Android中的ByteBuffer解析

    1. **分配缓冲区**:可以通过`ByteBuffer.allocate(int capacity)`来创建一个新的ByteBuffer,其中capacity参数指定缓冲区的大小。 2. **直接缓冲区**:对于性能敏感的应用,可以使用`ByteBuffer.allocateDirect...

    Java中的缓冲区(直接缓冲区、非直接缓冲区等).docx

    2. **通过`wrap`方法创建缓冲区**:这种方法可以将已有的数组或字节数组包装为缓冲区,例如: ```java byte[] byteArray = new byte[1024]; ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray); ``` #### 六...

    Java NIO学习笔记——ByteBuffer用法

    ByteBuffer是一个字节缓冲区,可以存储字节序列。在NIO中,所有的数据读写都通过缓冲区进行,ByteBuffer与其他类型的Buffer(如CharBuffer、IntBuffer等)一样,都继承自Buffer抽象类。它们都有共同的方法,如...

    nio学习demo 处理因缓冲区满导致写入失败问题

    7. `ByteBufferUtil.java`:ByteBuffer工具类,提供了一些帮助方法,如读写数据、清空缓冲区等,以方便操作ByteBuffer。 总的来说,这个示例通过NIO实现了客户端与服务器之间的高效通信,解决了TCP沾包问题,同时...

    ByteBuffer.zip

    - 写入数据:使用ByteBuffer的put方法将转换后的字节序列写入缓冲区,可以按单个字节、短整型、整型、长整型或其他自定义字节数组进行写入。 - 对齐处理:如果需要,可以进行字节对齐,确保数据按照特定的边界对齐...

    【IT十八掌徐培成】Java基础第26天-05.ByteBuffer-mark-pos-limit-cap-flip.zip

    首先,`ByteBuffer`是`Buffer`接口的一个实现,它是用来存储字节数据的缓冲区。`Buffer`家族还包括`CharBuffer`、`IntBuffer`等,分别对应不同的数据类型。 1. **Capacity**:容量是`Buffer`可以存储的最大数据量,...

    八位位组:一个使字节缓冲区工作变得轻松的库

    "八位位组"(Octet)是一个专为Clojure语言设计的库,它简化了字节缓冲区的工作,使得处理二进制数据变得更加高效和便捷。Clojure是一种基于Lisp的函数式编程语言,常用于开发高性能、并发的应用。 Octet库的核心...

    NIO学习系列:缓冲区更多特性及分散/聚集IO

    缓冲区在内存中分配一块区域,用于存储特定类型的值,如字节、字符、整数等。Java NIO提供了多种类型的缓冲区,包括ByteBuffer、CharBuffer、IntBuffer等,对应不同的数据类型。 1. 缓冲区的基本操作: - **分配**...

    protobuf+long+bytebuffer

    `long`类型在protobuf中用于表示大整数,而`ByteBuffer`则是protobuf.js提供的一种高效的数据缓冲区,用于进行二进制数据的读写。 首先,`protobuf.js`库提供了对protobuf数据类型的支持,包括基本类型(如int32、...

    Java NIO(通道+缓冲区+选择器)

    它包含一系列字节,有特定的容量,数据可以从通道读入缓冲区,然后从缓冲区写入通道。 2. **创建缓冲区**:Java NIO提供多个Buffer类,如ByteBuffer、CharBuffer、IntBuffer等,它们都继承自抽象类Buffer。每个...

    深入理解Apache Mina (6)---- Java Nio ByteBuffer与Mina ByteBuffer的区别

    Java NIO的ByteBuffer是Java标准库提供的一个核心类,它是通道(Channel)和缓冲区(Buffer)之间数据传输的主要媒介。它允许我们直接在内存中操作数据,而无需频繁地进行磁盘或网络I/O操作,提高了程序性能。ByteBuffer...

    易语言汇编版ByteBuffer源码

    在IT领域,ByteBuffer通常被用作一个高效的缓冲区,它可以存储和操作字节序列,尤其在处理网络通信时,能有效地组织和传输数据。易语言作为中国本土的一种编程语言,以其独特的“中文编程”特性,降低了编程的门槛,...

    Java NIO 主要类和方法(Java NIO中文版 附录C)

    - allocateDirect(int capacity): 分配一个新的直接字节缓冲区。 - array(): 返回此缓冲区的底层字节数组。 - arrayOffset(): 返回此缓冲区的底层字节数组的偏移量。 - asCharBuffer(): 将此缓冲区转换为CharBuffer...

    Android在JNI中使用ByteBuffer的方法

    同时,使用相同的ByteBuffer实例并清除或回绕它,可以避免频繁创建新缓冲区带来的性能损失。 总结来说,Android在JNI中使用ByteBuffer主要是为了提高数据传输的效率,通过直接访问内存,减少数据拷贝,从而提升应用...

    新IO缓冲区的输入和输出

    新IO缓冲区是Java 2平台标准版(J2SE)1.4引入的一个重要特性,也称为NIO(New IO)。NIO扩展了Java的I/O处理能力,提供了更高效、非阻塞的I/O操作。核心在于一系列的缓冲区类,它们构成了Java NIO的基础,使得数据...

    易语言-易语言汇编版ByteBuffer

    6. **分片与复制**:ByteBuffer可以创建视图(slice),生成一个新的缓冲区,它共享原始缓冲区的一部分数据。此外,还有复制缓冲区的方法,生成一个完全独立的新缓冲区。 7. **协议兼容性**:ByteBuffer的设计目的...

    java输入输出整理1

    在这个整理中,我们将深入探讨Java I/O中的关键概念,包括字节流、字符流、Java I/O框架图、通道和缓冲区的使用。 1. **字节流**: Java中的字节流主要用于处理原始的8位字节数据。字节流分为两种类型:输入流...

    取指定字节数组中的子数组 一个很好类例子

    我们可以创建一个`ByteBuffer`,然后使用`put()`方法填充数据,然后用`slice()`或`duplicate()`方法创建子缓冲区。例如: ```java ByteBuffer buffer = ByteBuffer.allocate(100); // 假设我们有100个字节 // ......

    ByteBufferBench:Java 字节缓冲区与 Julia 的比较

    针对我的 Julia ByteBuffer 对 Java ByteBuffer 实现进行基准测试。 Julia Version 0.4 Version 0.4.0-dev+2654 (2015-01-13 01:45 UTC) java version "1.8.0_25"均在 linux 上使用Intel:registered: Core:trade_...

    Java NIO核心概念总结篇

    直接字节缓冲区可以通过 `allocateDirect()` 方法创建。 ### 四、Java NIO 的三个核心组件 1. **Buffer(缓冲区)**:用于存储数据,是 NIO 中所有 I/O 操作的基础。 2. **Channel(通道)**:用于连接缓冲区和...

Global site tag (gtag.js) - Google Analytics