首页 > 其他分享 >ByteBuffer常用方法详解

ByteBuffer常用方法详解

时间:2022-11-27 15:33:43浏览次数:41  
标签:常用 buffer put 详解 limit ByteBuffer 缓冲区 position byte


缓冲区(Buffer)

 

缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对输入/输出(I/O)的数据作临时存储,这部分预留的内存空间就叫做缓冲区:

使用缓冲区有这么两个好处:

1、减少实际的物理读写次数

2、缓冲区在创建时就被分配内存,这块内存区域一直被重用,可以减少动态分配和回收内存的次数

举个简单的例子,比如A地有1w块砖要搬到B地

由于没有工具(缓冲区),我们一次只能搬一本,那么就要搬1w次(实际读写次数)

如果A,B两地距离很远的话(IO性能消耗),那么性能消耗将会很大

但是要是此时我们有辆大卡车(缓冲区),一次可运5000本,那么2次就够了

相比之前,性能肯定是大大提高了。

而且一般在实际过程中,我们一般是先将文件读入内存,再从内存写出到别的地方

这样在输入输出过程中我们都可以用缓存来提升IO性能。

所以,buffer在IO中很重要。在旧I/O类库中(相对java.nio包)中的BufferedInputStream、BufferedOutputStream、BufferedReader和BufferedWriter在其实现中都运用了缓冲区。java.nio包公开了Buffer API,使得Java程序可以直接控制和运用缓冲区。

在Java NIO中,缓冲区的作用也是用来临时存储数据,可以理解为是I/O操作中数据的中转站。缓冲区直接为通道(Channel)服务,写入数据到通道或从通道读取数据,这样的操利用缓冲区数据来传递就可以达到对数据高效处理的目的。在NIO中主要有八种缓冲区类(其中MappedByteBuffer是专门用于内存映射的一种ByteBuffer):

ByteBuffer常用方法详解_数据

Fields

 

所有缓冲区都有4个属性:capacity、limit、position、mark,并遵循:mark <= position <= limit <= capacity,下表格是对着4个属性的解释:

属性

描述

Capacity

容量,即可以容纳的最大数据量;在缓冲区创建时被设定并且不能改变

Limit

表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作。且极限是可以修改的

Position

位置,下一个要被读或写的元素的索引,每次读写缓冲区数据时都会改变改值,为下次读写作准备

Mark

标记,调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置

Methods

 

1、实例化

java.nio.Buffer类是一个抽象类,不能被实例化。Buffer类的直接子类,如ByteBuffer等也是抽象类,所以也不能被实例化。

但是ByteBuffer类提供了4个静态工厂方法来获得ByteBuffer的实例:

方法

描述

allocate(int capacity)

从堆空间中分配一个容量大小为capacity的byte数组作为缓冲区的byte数据存储器

allocateDirect(int capacity)

是不使用JVM堆栈而是通过操作系统来创建内存块用作缓冲区,它与当前操作系统能够更好的耦合,因此能进一步提高I/O操作速度。但是分配直接缓冲区的系统开销很大,因此只有在缓冲区较大并长期存在,或者需要经常重用时,才使用这种缓冲区

wrap(byte[] array)

这个缓冲区的数据会存放在byte数组中,bytes数组或buff缓冲区任何一方中数据的改动都会影响另一方。其实ByteBuffer底层本来就有一个bytes数组负责来保存buffer缓冲区中的数据,通过allocate方法系统会帮你构造一个byte数组

wrap(byte[] array,

 int offset, int length)

在上一个方法的基础上可以指定偏移量和长度,这个offset也就是包装后byteBuffer的position,而length呢就是limit-position的大小,从而我们可以得到limit的位置为length+position(offset)

 


我写了这几个方法的测试方法,大家可以运行起来更容易理解



​​

1. public static void main(String args[]) throws FileNotFoundException {  
2.
3. "----------Test allocate--------");
4. "before alocate:"
5. + Runtime.getRuntime().freeMemory());
6.
7. // 如果分配的内存过小,调用Runtime.getRuntime().freeMemory()大小不会变化?
8. // 要超过多少内存大小JVM才能感觉到?
9. 102400);
10. "buffer = " + buffer);
11.
12. "after alocate:"
13. + Runtime.getRuntime().freeMemory());
14.
15. // 这部分直接用的系统内存,所以对JVM的内存没有影响
16. 102400);
17. "directBuffer = " + directBuffer);
18. "after direct alocate:"
19. + Runtime.getRuntime().freeMemory());
20.
21. "----------Test wrap--------");
22. byte[] bytes = new byte[32];
23. buffer = ByteBuffer.wrap(bytes);
24. System.out.println(buffer);
25.
26. 10, 10);
27. System.out.println(buffer);
28. }



 

2、另外一些常用的方法

 

方法

描述

limit(), limit(10)等

其中读取和设置这4个属性的方法的命名和jQuery中的val(),val(10)类似,一个负责get,一个负责set

reset()

把position设置成mark的值,相当于之前做过一个标记,现在要退回到之前标记的地方

clear()

position = 0;limit = capacity;mark = -1;  有点初始化的味道,但是并不影响底层byte数组的内容

flip()

limit = position;position = 0;mark = -1;  翻转,也就是让flip之后的position到limit这块区域变成之前的0到position这块,翻转就是将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态

rewind()

把position设为0,mark设为-1,不改变limit的值

remaining()

return limit - position;返回limit和position之间相对位置差

hasRemaining()

return position < limit返回是否还有未读内容

compact()

把从position到limit中的内容移到0到limit-position的区域内,position和limit的取值也分别变成limit-position、capacity。如果先将positon设置到limit,再compact,那么相当于clear()

get()

相对读,从position位置读取一个byte,并将position+1,为下次读写作准备

get(int index)

绝对读,读取byteBuffer底层的bytes中下标为index的byte,不改变position

get(byte[] dst, int offset, int length)

从position位置开始相对读,读length个byte,并写入dst下标从offset到offset+length的区域

put(byte b)

相对写,向position的位置写入一个byte,并将postion+1,为下次读写作准备

put(int index, byte b)

绝对写,向byteBuffer底层的bytes中下标为index的位置插入byte b,不改变position

put(ByteBuffer src)

用相对写,把src中可读的部分(也就是position到limit)写入此byteBuffer

put(byte[] src, int offset, int length)

从src数组中的offset到offset+length区域读取数据并使用相对写写入此byteBuffer

 

 

 

以下为一些测试方法:

 


​​ 

1. public static void main(String args[]){
2.
3. "--------Test reset----------");
4. buffer.clear();
5. 5);
6. buffer.mark();
7. 10);
8. "before reset:" + buffer);
9. buffer.reset();
10. "after reset:" + buffer);
11.
12. "--------Test rewind--------");
13. buffer.clear();
14. 10);
15. 15);
16. "before rewind:" + buffer);
17. buffer.rewind();
18. "before rewind:" + buffer);
19.
20. "--------Test compact--------");
21. buffer.clear();
22. "abcd".getBytes());
23. "before compact:" + buffer);
24. new String(buffer.array()));
25. buffer.flip();
26. "after flip:" + buffer);
27. char) buffer.get());
28. char) buffer.get());
29. char) buffer.get());
30. "after three gets:" + buffer);
31. "\t" + new String(buffer.array()));
32. buffer.compact();
33. "after compact:" + buffer);
34. "\t" + new String(buffer.array()));
35.
36. "------Test get-------------");
37. 32);
38. byte) 'a').put((byte) 'b').put((byte) 'c').put((byte) 'd')
39. byte) 'e').put((byte) 'f');
40. "before flip()" + buffer);
41. // 转换为读取模式
42. buffer.flip();
43. "before get():" + buffer);
44. char) buffer.get());
45. "after get():" + buffer);
46. // get(index)不影响position的值
47. char) buffer.get(2));
48. "after get(index):" + buffer);
49. byte[] dst = new byte[10];
50. 0, 2);
51. "after get(dst, 0, 2):" + buffer);
52. "\t dst:" + new String(dst));
53. "buffer now is:" + buffer);
54. "\t" + new String(buffer.array()));
55.
56. "--------Test put-------");
57. 32);
58. "before put(byte):" + bb);
59. "after put(byte):" + bb.put((byte) 'z'));
60. "\t" + bb.put(2, (byte) 'c'));
61. // put(2,(byte) 'c')不改变position的位置
62. "after put(2,(byte) 'c'):" + bb);
63. "\t" + new String(bb.array()));
64. // 这里的buffer是 abcdef[pos=3 lim=6 cap=32]
65. bb.put(buffer);
66. "after put(buffer):" + bb);
67. "\t" + new String(bb.array()));
68. }

标签:常用,buffer,put,详解,limit,ByteBuffer,缓冲区,position,byte
From: https://blog.51cto.com/u_13991401/5890081

相关文章

  • 二. Dockerfile构建镜像参数详解、Docker镜像分层构建案例 -1
    镜像简介: docker镜像基于unionfilesystem将多个目录合并挂载至一个目录给容器使用。docker镜像只有rootfs而没有内核、运行使用的是宿主机的bootfs。  rootfs(root......
  • 动态规划算法图文详解(Kotlin语言):二维矩阵中找到只包含 1 的最大正方形(LeetCode-22
    题目描述在一个由0和1组成的二维矩阵内,找到只包含1的最大正方形,并返回其面积。示例:输入:1010010 ​​​11​​​ 111 ​​​11​​​ 110010输出:4......
  • Service详解之Service介绍
    Service介绍在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。为了解......
  • 【ClickHouse 内核原理图文详解】关于分区、索引、标记和压缩数据的协同工作...
    概述ClickHouse是一个用于联机分析处理(OLAP)的列式数据库管理系统(ColumnarDBMS)。分区、索引、标记和压缩数据,这些组件配合在一起给ClickHouse数据库带来非常高效的查询......
  • Hadoop Shell 命令详解
    HadoopShell命令​​FSShell​​​​cat​​​​chgrp​​​​chmod​​​​chown​​​​copyFromLocal​​​​copyToLocal​​​​cp​​​​du​​​​dus​​​​exp......
  • 13-常用API
    typora-root-url:images一、API1.1、概述​ Java的API(API:Application(应用)Programming(程序)Interface(接口))​ JavaAPI就是JDK中提供给我们使用的类,这些类......
  • 跨公司采购转储详解(图文)(转)
    业务情景:同一集团下的两个公司1100与2100之间的采购业务。1100下设工厂1101,2100下设工厂2101。供货公司1100须先送货到订单公司2100的仓库,然后2100公司再按集团外客户的要......
  • Java中Collections.sort()方法详解
     时间:2022/11/27 在我们写算法题的时候有时需要对给定的List列表进行排序,这样方便之后的操作,此时我们可以用到Collections类中的sort方法,JavaAPI文档中对该方......
  • JavaScript中String的match方法详解
     String.prototype.match()**String.prototype.match()方法返回通过一个正则表达式匹配到的字符串结果。**​​var='Thequickbrownfoxjumpsoverthelazydog.Itba......
  • 草根教程 网友详解索尼本本装雪豹过程
       安装环境:VPCEB100C、I3CPU、2G内存、5650显卡、320G硬盘、WIN7旗舰64位、VMwareWorkstation7.0.1build-227600。   所需软件:   1.MacOSX10.6.3光盘镜像......