bytebuffer常用方法_bytebuffer.get

bytebuffer常用方法_bytebuffer.getByteBuffer的心得

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

NIO,数据的读写操作始终是与缓冲区相关联的(读取时信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲区)

缓冲区是定长的,基本上它只是一个列表,它的所有元素都是基本数据类型String并未包含其中,但是String. getBytes就可以了.

 

Nio缓冲区的7种形式

ByteBuffer 

ShortBuffer 
  IntBuffer 
  CharBuffer 
  FloatBuffer 
  DoubleBuffer 
  LongBuffer 

 

 

 

     ByteBuffer是最常用的缓冲区,它提供了读写其他数据类型的方法,且信道的读写方法只接收ByteBuffer

ByteBuffer的属性中:有以下3种常见属性

m:mark:初始值为-1,标记索引地点

p:position:初始值为0,索引下标

l:limit:最好定义成bytebuffer的长度,即允许可读空间长度

c:capacity:缓冲区能容纳的数据元素的最大数量,创建之后无法被改变

总的关系m

 

 

 

1.       创建ByteBuffer
1.1
 使用allocate()静态方法

//创建一个容量为256字节的ByteBuffer,

ByteBuffer buffer=ByteBuffer.allocate(256);

        参数为ByteBuffer的长度,这个一定要在前期设计时考虑充足,不然就得重新创建

创建其他缓冲区也是这样的静态方法创建的Buffer父类引用对象 。

 

1.2 通过包装一个已有的数组来创建如下,通过包装的方法创建的缓冲区保留了被包装数组内保存的数据.
    ByteBuffer buffer=ByteBuffer.wrap(byteArray);

      // wrap(int[] array, int offset, int length)
      无论要使用的子数组的偏移量offset ,还是子数组的长度length ,使用这个方法的过程都是缓冲整个数组的过程。
      而且buffer与数组创建强耦合联系,数据改变则缓冲区值也会改变,反之亦然

 

 如果要将一个字符串存入ByteBuffer,可以如下操作:
    String sendString=”
你好,服务器. “;
    ByteBuffer sendBuffer=ByteBuffer.wrap(sendString.getBytes(“UTF-8”));

        //ByteBuffer中读出String

       Charset cs = Charset.forName (“UTF-8”);

        byte[] bs = new byte[sendBuffer. limit()];

        sendBuffer.get(bs);

        String news = new String(bs, cs);

//String news = new String(sendBuffer.array(), cs);

注释里的方法也是可行,只是要注意array()方法不是将ByteBufferpositionlimit段的byte[]数组输出,而是输出缓存区所有的byte[]数组!包括limit之后的!

 

 

2.回绕缓冲区
  buffer.flip();

byte[] data = new byte[buffer.remaining()];

    buffer.get(data);      

//  session开始写入数据

    WriteFuture writeFuture = session.write(data);
  这个方法用来将缓冲区准备为数据传出状态,执行以上方法后,输出通道会从数据的开头而不是末尾开始.回绕保持缓冲区中的数据不变,只是准备写入而不是读取.

3.清除缓冲区
  buffer.clear();
 
 这个方法实际上也不会改变缓冲区的数据,而只是简单的重置了缓冲区的主要索引值.不必为了每次读写都创建新的缓冲区,那样做会降低性能.相反,要重用现在的缓冲区,在再次读取之前要清除缓冲区.说白了就是mark=-1position=0的过程

以下为常用方式
4.
从套接字通道(信道)读取数据
   SocketChannel
采用的是非阻塞异步读取流数据,在读取的时候,通常是

ByteBuffer.clear();

SocketChannel.read(ByteBuffer);

执行以上方法后,通道会从socket读取的数据填充此缓冲区,它返回成功读取并存储在缓冲区的字节数.在默认情况下,这至少会读取一个字节,或者返回-1指示数据结束.

  如果流中有数据,就会把数据从position开始读到ByteBuffer中,在读取之前ByteBufferclear操作会把position置为0,limit置为capability,也就是相当于清空了之前的内容,但是ByteBuffer中数组的内容在read之前是没有改变的.

read之后,通常就是开始从ByteBuffer中提取读到的数据,如果你的数据是以自己定义的数据包的格式进行发送的,那你还需要判断是否读到了数据包的结尾,因为对流数据本身来说是没有结尾这一说的。在提取数据之前,要先把position放到开始读取时的位置,limit放到当前位置,所以要flip一下,表示从positionlimit的位置都是需要的数据。

ByteBuffer.flip();

while(ByteBuffer.hasRemaining()){

  byte c=ByteBuffer.get();

  if (b == PACKAGE_END) {

      //you can return the package here

  }else{

      //you can append the byte here.like StringBuilder.append().

  }

}

这样以来也存在一个问题,当一次读到的ByteBuffer不包含完整的数据包或者包含多个数据包.那么就需要在下一次继续把这些包分拆出来.那么在读取数据的代码处就可以改为,这样就把之前读取到的未完整的包保留了下来:

if(!ByteBuffer.hasRemaining){

    ByteBuffer.clear();

    SocketChannel.read(ByteBuffer);

}

另外一个可能会用到的操作就是ByteBuffer.rewind(),他会把position置为0limit保持不变,可以用于重复读取一段数据.

 

 

5.向套接字通道(信道)写入数据
  socketChannel.write(buffer);
 
 此方法以一个ByteBuffer为参数,试图将该缓冲区中字节写入信道.

 

6.ByteBuffer与字符的互转

   

private byte[] getBytes (char[] chars) {//将字符转为字节(编码)
   Charset cs = Charset.forName (“UTF-8”);
   CharBuffer cb = CharBuffer.allocate (chars.length);
   cb.put (chars);
   cb.flip ();
   ByteBuffer bb = cs.encode (cb)
   return bb.array();
}

private char[] getChars (byte[] bytes) {//将字节转为字符(解码)

Charset cs = Charset.forName (“UTF-8”);

ByteBuffer bb = ByteBuffer.allocate (bytes.length);

bb.put (bytes);

bb.flip ();

CharBuffer cb = cs.decode (bb);

return cb.array();
}

 

7. put()方法远比想象的强大

    buff.put();可以根据数据类型做相应调整

    比如buff.putChar(chars),buff.putDouble(double)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/186833.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Linux中退出编辑模式的命令

    Linux中退出编辑模式的命令vim有三种模式,注意:这三种模式有很多不同的叫法,我这里是按照鸟哥的linux书中的叫法。一般指令模式、编辑模式、指令列命令模式1.vim文件名进入一般模式;2.按i进行编辑进入编辑模式;(或者I,o,O,a,A,r,R)3.编辑结束,按ESC键跳到一般模式模式;4.按:进入指令列命令模式;进入指令列模式…

  • MySQL连接查询

    MySQL连接查询首先创建两个表fruits表,包含水果id、名字、价格orders表,包含id和订单号(num)1.内连接查询(INNORJOIN)使用普通sql语句selectfruits.id,name,price,numfromfruits,orderswherefruits.id=orders.id;使用内连接查询语句(结果与上图相同)s…

  • pytest运行_python压测

    pytest运行_python压测前言pytest运行完用例之后会生成一个.pytest_cache的缓存文件夹,用于记录用例的ids和上一次失败的用例。方便我们在运行用例的时候加上–lf和–ff参数,快速运行上一

  • 如何开发一款游戏:游戏开发流程及所需工具

    如何开发一款游戏:游戏开发流程及所需工具本文来自作者goto先生在GitChat上分享「如何开发一款游戏:游戏开发流程及所需工具」,「阅读原文」查看交流实录。「文末高能」编辑|哈比游戏作为娱乐生活的一个方面,参与其中的人越来越多,而大部分参与其中的人都是以玩家的身份。他们热爱一款游戏,或是被游戏的故事情节、炫丽的场景、动听的音乐所艳羡,亦或是被游戏中角色扮演、炫酷的技能、有趣的任务所吸引,然而他们中的大多数可能并不了解如此

  • 多线程之儿子买盐问题

    多线程之儿子买盐问题

  • idea快捷键和vscode快捷键对比

    idea快捷键和vscode快捷键对比之前一直写后端,最近用vscode写vue,两边的快捷键差异还挺大的,怎么感觉webstorm也挺香呢【手动狗头】快捷键名称IntelliJIDEAVisualStudioCode复制一行Ctrl+CCtrl+C剪切一行Ctrl+XCtrl+X删除一行Ctrl+YCtrl+Shift+K向下复制行Ctrl+DAlt+Shift+⬇上下移动行Alt+Shift+⬆⬇Alt+⬆⬇向

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号