ByteBuffer作为JDK的字节流处理对象,这里举个小例子说明下用法,直接上代码:

package com.wlf.netty.nettyserver;

import org.junit.Assert;
import org.junit.Test; import java.nio.ByteBuffer; public class ByteBufferTest { @Test
public void byteBufferTest() { // 写入消息体
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
byteBuffer.putInt(0xabef0101);
byteBuffer.putInt(1024); // 今天过节
byteBuffer.put((byte) 1);
byteBuffer.put((byte) 0); // 读取消息头,因为写完后position已经到10了,所以需要先反转为0,再从头读取
byteBuffer.flip();
printDelimiter(byteBuffer); // 读取length
printLength(byteBuffer); // 继续读取剩下数据
byteBuffer.get();
byteBuffer.get();
printByteBuffer(byteBuffer); // 我再反转一下,我还可以从头开始读
byteBuffer.flip();
printDelimiter(byteBuffer); // clear清空一下,再从头开始读
byteBuffer.clear();
printDelimiter(byteBuffer); // rewind重绕一下
byteBuffer.rewind();
printDelimiter(byteBuffer); // mark标记一下
byteBuffer.mark(); // 再读取length
printLength(byteBuffer); // reset重置,回到读取delimiter的地方
byteBuffer.reset();
printByteBuffer(byteBuffer);
} private void printDelimiter(ByteBuffer buf) {
int newDelimiter = buf.getInt();
System.out.printf("delimeter: %s\n", Integer.toHexString(newDelimiter));
printByteBuffer(buf);
} private void printLength(ByteBuffer buf) {
int length = buf.getInt();
System.out.printf("length: %d\n", length);
printByteBuffer(buf);
} private void printByteBuffer(ByteBuffer buf) {
System.out.printf("position: %d, limit: %d, capacity: %d\n", buf.position(), buf.limit(), buf.capacity());
}
}

  输出结果:

delimeter: abef0101
position: 4, limit: 10, capacity: 10
length: 1024
position: 8, limit: 10, capacity: 10
position: 10, limit: 10, capacity: 10
delimeter: abef0101
position: 4, limit: 10, capacity: 10
delimeter: abef0101
position: 4, limit: 10, capacity: 10
delimeter: abef0101
position: 4, limit: 10, capacity: 10
length: 1024
position: 8, limit: 10, capacity: 10
position: 4, limit: 10, capacity: 10 Process finished with exit code 0

  ByteBuffer的索引是唯一的。像上面的例子,初始索引是0,写完索引值为9,为了读取写入的值,我们再重新设置索引为0(调用flip方法)。ByteBuffer有4个索引值,分别是:

  mask:就是你标记的索引,标记唯一的作用是调用reset重置回到过去

  position:当前位置的索引,mask标记任何时候都不会大于position,因为你必须先读到当前位置之后,才能标记该位置;同时position也不能超过limit限制

  limit:第一个不应该读取或写入的元素的索引,也就是读写禁地,默认是最大容量,如果你设置该值,那么理所让然它不能超过最大容量capacity

  capacity:这个就不解释了

  它们的大小关系始终是:

  mask <= position <= limit <= capacity

  我们上面的例子中就是capacity=limit。

  初始索引:

  +-----------------------------------------------------+

/                            bytes                              /

+-----------------------------------------------------+

/                            10                                  /

  0=position                                               10=limit=capacity

  我们写入delimiter之后:

  +----------------+------------------------------------+

/      delimiter /     other  bytes                       /

+----------------+------------------------------------+

/             4     /          6                                    /

   0        4=position                                     10=limit=capacity

  

  至于反转flip如何切换读写模式、reset如何重置标记、clear清除如何重新设置索引值为0、rewind重绕如何让你重新读取,都不会动内容,所以你会看到上面不管怎么折腾我们都可以重复取出delimiter、length的值。看下源码就一清二楚了,无非就是对上面4个索引值进行赋值而已:

    /**
* Resets this buffer's position to the previously-marked position.
*
* <p> Invoking this method neither changes nor discards the mark's
* value. </p>
*
* @return This buffer
*
* @throws InvalidMarkException
* If the mark has not been set
*/
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
} /**
* Clears this buffer. The position is set to zero, the limit is set to
* the capacity, and the mark is discarded.
*
* <p> Invoke this method before using a sequence of channel-read or
* <i>put</i> operations to fill this buffer. For example:
*
* <blockquote><pre>
* buf.clear(); // Prepare buffer for reading
* in.read(buf); // Read data</pre></blockquote>
*
* <p> This method does not actually erase the data in the buffer, but it
* is named as if it did because it will most often be used in situations
* in which that might as well be the case. </p>
*
* @return This buffer
*/
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
} /**
* Flips this buffer. The limit is set to the current position and then
* the position is set to zero. If the mark is defined then it is
* discarded.
*
* <p> After a sequence of channel-read or <i>put</i> operations, invoke
* this method to prepare for a sequence of channel-write or relative
* <i>get</i> operations. For example:
*
* <blockquote><pre>
* buf.put(magic); // Prepend header
* in.read(buf); // Read data into rest of buffer
* buf.flip(); // Flip buffer
* out.write(buf); // Write header + data to channel</pre></blockquote>
*
* <p> This method is often used in conjunction with the {@link
* java.nio.ByteBuffer#compact compact} method when transferring data from
* one place to another. </p>
*
* @return This buffer
*/
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
} /**
* Rewinds this buffer. The position is set to zero and the mark is
* discarded.
*
* <p> Invoke this method before a sequence of channel-write or <i>get</i>
* operations, assuming that the limit has already been set
* appropriately. For example:
*
* <blockquote><pre>
* out.write(buf); // Write remaining data
* buf.rewind(); // Rewind buffer
* buf.get(array); // Copy data into array</pre></blockquote>
*
* @return This buffer
*/
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}

ByteBuffer使用实例的更多相关文章

  1. ByteBuffer常用方法详解

    原文  http://blog.csdn.net/u012345283/article/details/38357851 缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对输入/输出(I/ ...

  2. ByteBuf使用实例

    之前我们有个netty5的拆包解决方案(参加netty5拆包问题解决实例),现在我们采用另一种思路,不需要新增LengthFieldBasedFrameDecoder,直接修改NettyMessage ...

  3. JAVA NIO缓冲区(Buffer)------ByteBuffer常用方法

    参考:https://blog.csdn.net/xialong_927/article/details/81044759 缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对输入/输出(I ...

  4. Java性能优化之使用NIO提升性能(Buffer和Channel)

    在软件系统中,由于IO的速度要比内存慢,因此,I/O读写在很多场合都会成为系统的瓶颈.提升I/O速度,对提升系统整体性能有着很大的好处. 在Java的标准I/O中,提供了基于流的I/O实现,即Inpu ...

  5. Java NIO Buffer(netty源码死磕1.2)

    [基础篇]netty源码死磕1.2:  NIO Buffer 1. Java NIO Buffer Buffer是一个抽象类,位于java.nio包中,主要用作缓冲区.Buffer缓冲区本质上是一块可 ...

  6. JAVA NIO学习笔记二 频道和缓冲区

    Java NIO 频道 Java NIO渠道类似于流,他们之间具有一些区别的: 您可以读取和写入频道.流通常是单向(读或写). 通道可以异步读取和写入数据. 通道常常是读取或写入缓冲区. 如上所述,您 ...

  7. LWJGL3的内存管理,第一篇,基础知识

    LWJGL3的内存管理,第一篇,基础知识 为了讨论LWJGL在内存分配方面的设计,我将会分为数篇随笔分开介绍,本篇将主要介绍一些大方向的问题和一些必备的知识. 何为"绑定(binding)& ...

  8. 最近学习工作流 推荐一个activiti 的教程文档

    全文地址:http://www.mossle.com/docs/activiti/ Activiti 5.15 用户手册 Table of Contents 1. 简介 协议 下载 源码 必要的软件 ...

  9. RPC原理及RPC实例分析

    在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 1 2 3 4 5 6 public class ...

随机推荐

  1. 在动态sql的使用where时,if标签判断中,如果实体类中的某一个属性是String类型,那么就可以这样来判断连接语句:

    在动态sql的使用where时,if标签判断中,如果实体类中的某一个属性是String类型,那么就可以这样来判断连接语句: 如果是String类型的字符串进行判空的时候: <if test=&q ...

  2. Java集合之整体概述

    Java集合与数组是相似的,都用于保存一组对象,并提供一些操作来管理对象.然而,不同于数组的是,当添加或删除元素时集合的大小是可以自动变化的.Java集合不可以存放基本类型数据(比如int,long或 ...

  3. oracle数据库锁表

    在团队开发一个项目的时候,避免不了两个或两个以上的人同时操作某一数据库中的同一张表,这时候,如果一个用户没有提交事务,或者忘记提交事务,那么其他用户就不能对这张表进行操作了,这是很烦人的事情,下面是查 ...

  4. tensorflow 运行效率 GPU memory leak 问题解决

    问题描述: Tensorflow 训练时运行越来越慢,重启后又变好. 用的是Tensorflow-GPU 1.2版本,在GPU上跑,大概就是才开始训练的时候每个batch的时间很低,然后随着训练的推进 ...

  5. if __name__ == "__main__",python主程序入口

    https://blog.csdn.net/liukai2918/article/details/79465671

  6. TPCH 22条SQL语句分析

    使用TPC-H进行性能测试,需要有很多工作配合才能获得较高性能,如建立索引,表数据的合理分布(使用表空间和聚簇技术)等.本文从查询优化技术的角度,对TPC-H的22条查询语句和主流数据库执行每条语句对 ...

  7. webuploader+web如何实现分片+断点续传

    众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路. 实现文件夹 ...

  8. C# 异常 抛异常的时候 同时抛出 传入的参数

    abp的审计日志都把这些功能实现了 可以借鉴 抛异常的时候 同时抛出 传入的参数 大致这样实现,aop,方法执行先,先把参数写入到栈中,抛异常时,栈中自然就有此时的参数了. 可用于重现该异常. 获取把 ...

  9. 【概率论】6-1:大样本介绍(Large Random Samples Introduction)

    title: [概率论]6-1:大样本介绍(Large Random Samples Introduction) categories: - Mathematic - Probability keyw ...

  10. [HackTheBox]WEB题目

    0x01 [50 Points] I know Mag1k 问题描述: Can you get to the profile page of the admin? 访问分配的地址,是一个带注册的登入页 ...