Java NIO ByteBuffer 的使用与源码研究

Java ByteBuffer使用全解析 ByteBuffer是 Java NIO(New I/O)库中的一个类,用于处理字节数据。它提供了一种灵活且高效的方式来操作字节缓冲区,适用于处理大量的字节数据,例如文件 I/O、网络通信等。ByteBufferByteBuffer有一个固定的容量,一旦分配,就不能更改。可以通过allocate静态方法或wrap静态方法来创建一个ByteBuffer。// 分配 1024 字节的缓冲区ByteBuffer有一个位置和限制的概念,它们用于跟踪读写的位置。position表示下一个要读写的位置,而limit。 阅读详情

一、结论

  ByteBuffer 是Java NIO体系中的基础类,所有与Channel进行数据交互操作的都是以ByteBuffer作为数据的载体(即缓冲区)。ByteBuffer的底层是byte数组,通过四个重要的成员变量(mark、limit、position、capacity)来实现对缓冲区的读写数据以及复用缓冲区等操作。ByteBuffer  申请缓冲区内存(数组)的方式有两种,即堆内存与堆外内存,其中堆外内存有着较强的性能,但需要小心处理,堆内存则可以放心的交给JVM管理。此外还需要注意一点的是ByteBuffer是非线程安全的。

二、API研究

  学习新知识总归要回到其本质上,首先思考以下问题:

  如果使用一个数组作为缓冲区,想要复用这个缓冲区需要作什么?

  在这里我们以阻塞IO读写文件来说明(代码如下所示)

  我们新建了一个数组作为缓冲区,读文件的时候不断的往该缓冲区写入数据,并记录实际读入的字节数,并将实际读入的字节数写入byteOutputStream。

  可以看出要想使用一个数组作为缓冲区首先我们至少需要以下数据

    1.缓冲区的大小(buffer.length)

    2.缓冲区内可用的字节数(即readLength,因为不可能每次读入数据都填满整个缓冲区)

    此外,由于InputStream可以将数据读到缓冲区的指定分段,因此缓冲区内可用的字节数实际上是由一个数组下标值(默认为0)加上实际读入的字节数长度组成的。

复制代码

 1     public static void main() throws IOException {
 2         byte[] buffer = new byte[1024];
 3         ByteOutputStream byteOutputStream = new ByteOutputStream();
 4 
 5         File file = new File("D:/tmp/test");
 6         FileInputStream inputStream = new FileInputStream(file);
 7         int readLength = 0;
 8         while ((readLength = inputStream.read(buffer)) != 0){
 9             // do something
10             byteOutputStream.write(buffer,0,readLength);
11         }
12         inputStream.close();
13         System.out.println(new String(byteOutputStream.getBytes()));
14     }

复制代码

  因此,ByteBuffer 作为可以复用的缓冲区,其底层也是使用数组作为缓冲区,其核心主要有以下四个成员变量

    // Invariants: mark <= position <= limit <= capacity
    private int mark = -1;
    private int position = 0;
    private int limit;
    private int capacity;

  mark 标记

  position 位置,当前数组指针所在的位置,即下一个读出\写入数组元素的指针所在位置

  limit 缓冲区的限制,第一个不应该向此缓冲区写入\读出数据的位置(对应readLength)(默认等于capacity)

  capacity 缓冲区的实际大小(对应buffer.length)

  因此ByteBuffer 的API主要是围绕围绕这四个成员变量开展的。

  

  1.以remaining举例说明(该方法用于获取剩余元素的大小)

    public final int remaining() {
        return limit - position;
    }

   

      (图片来自《NIO与Socket编程指南》)

    如上图所示此时 capacity = 8,limit = 6,position = 2 ,以读数据为例则说明此时还有4个元素可供读取。

 

  2.ByteBuffer 复用的实现

  参考阻塞读写文件例子可以确定要复用ByteBuffer必然要重置相关的变量,重置不同的变量有着不同的效果。

  比如,在向ByteBuffer中写入数据之后,要再读出数据时必然需要知道实际写入数据的长度(limit并不会随着写入数据而改变,limit代表了缓冲区的限制),并且将数组指针移动到0的位置。

  filp方法就是干这活的,其实现如下:

复制代码

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
}

复制代码

  要还原缓冲区的状态,直接调用clear即可,但该方法并不会清除缓冲区中的数据

复制代码

public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
 }

复制代码

  如果在读取数据的过程(此时postion已经改变)想要再次从头读取数据只需重置postion即可,使用rewind方法即可,该方法会重置mark为-1。

public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }

  3.Mark 一下

  从设计上来说ByteBuffer并不是一个支持随机访问(RandomAccess)的缓冲区,写入或读出数据的时候数组的指针只能向前移动,但在某些场景下我们可能需要对某个数据段的内容进行重复读取,此时只需要对指定的位置执行标记操作以便需要的时候将指针移动到标记的位置。

  mark方法如下所示,只是暂存position,并不会改变指针的位置。

    public final Buffer mark() {
    mark = position;
    return this;
    }

  因此如果想要回到该位置就需要执行reset方法。

复制代码

public final Buffer reset() {
    int m = mark;
    if (m < 0)
        throw new InvalidMarkException();
    position = m;
    return this;
}

复制代码

  由于mark的默认值为-1,因此如果未执行过mark方法会抛出异常。

 

    Q  Q交流群: 点击 有任何问题可以加群交流   

    Java最新一线架构技术讲解请:点击 内容实用 讲解简单易懂

Java NIO详细总结(源码解析) 目录 NIO概述 I/O与NIO区别 FileChannel和ByteBuffer的使用 ByteBuffer 创建ByteBuffer对象 ByteBuffer如何写入/读取数据 视图缓冲区 ByteOrder FileChannel 创建FileCHannel对象 FileChannel如何写入数据 FileChannel文件加锁 文件映射 参考文献 NIO概述 ... 阅读详情

相关推荐

JMeter压测Dubbo接口的完整落地方案(适配3.x)

Dubbo作为主流Java微服务RPC框架,其接口压测长期面临协议私有、注册发现复杂、序列化耦合度高等技术门槛。理解Dubbo基于TCP长连接、泛化调用与SPI扩展机制的核心原理,是实现稳定压测的前提;技术价值在于绕过HTTP网关直击服务核心链路,保障大促等关键场景的性能可信度;典型应用场景包括电商订单链路压测、风控/库存等内部Dubbo服务SLA验证,以及CI/CD中性能左移实践。本文聚焦Dubbo 3.x版本,提供零第三方插件、可复用、避坑的JMeter Java Sampler落地路径。

weixin_33700809的博客 549

Java SocketChannel控制接收数据字节长度及复用ByteBuffer

Java SocketChannel控制接收数据字节长度及复用ByteBuffer 引言 混乱的数据结构 尝试读取固定大小数据 如何复用ByteBuffer 文件传输Buffer复用及减少使用用户层缓冲区

Doub1's Blog 3234

【PMP认证考试之个人总结】第 4 章 项目范围管理

第 4 章 项目范围管理 4.1 综述   1.产品范围和项目范围的区别 ①产品范围:某项产品、服务或成果所具有的特性和功能; ②项目范围:为交付具有规定特性与功能的产品、服务或成果而必须完成的工作; 2.收集需求、定义范围和创建WBS输出的区别 ①收集需求 ===> 需求跟踪矩阵; ②定义范围 ===> 项目范围说明书;

qq296398300的博客 2891

【源码篇】Kafka生产者内存管理BufferPool

我们都知道kafka生产者Send一条记录并没有直接发送到kafka服务端,而是先将它保存到内存 (RecordAccumulator) 中,用于压缩之后批量发送,这里内存的创建和释放是比较消耗资源的,为了实现内存的高效利用,基本上每个成熟的框架或者工具都有一套内存管理机制,kafka的生产者使用 BufferPool 来实现内存 (ByteBuffer) 的复用。 红色和绿色的总和代表 BufferPool 的总量,用totalMemory表示(由buffer.memory配置);绿色代表可使用的空间,

数据工匠记 3346

新版股票配资系统源码/股票分析系统技术方案

新版股票配资系统;全套源码支持新股申购功能,包含C#+MySQL开发的后台系统及Spring框架,采用C/S架构。注意:本源码仅限技术学习、功能测试及模拟交易使用,严禁用于非法用途,违者责任自负。

q318136906的博客 1643

AI原生应用在UGC内容审核中的实战经验

AI原生应用(AI-Native Application)——以机器学习模型为核心驱动力,深度整合数据、算法、工程架构的完整系统——为破解这一三角难题提供了全新范式。全链路数据驱动:从数据采集、模型训练到决策优化,形成闭环自治系统,无需人工规则干预多模态深度理解:同时处理文本、图像、音频、视频等多类型内容,理解语义而非简单匹配特征自适应进化能力:通过人机协同反馈持续学习新型违规模式,模型周级迭代成为常态审核效率提升300%:单条视频审核耗时从2.3秒降至0.7秒。

AI算力网络与通信的博客 1149

Java NIO 介绍,多路复用模型,ByteBuffer 基本使用,粘包问题,半包问题,Selector 监听机制

Java NIO 介绍,多路复用模型,ByteBuffer 基本使用,粘包问题,半包问题,Selector 监听机制

Harvey's Blog 2638

【仓颉 + 鸿蒙 + AI Agent】CangjieMagic框架(3):Agent请求和响应

CangjieMagic框架:使用华为仓颉编程语言编写,专门用于开发AI Agent,支持鸿蒙、Windows、macOS、Linux等系统。这篇文章剖析一下 CangjieMagic 框架中的 AgentRequest 和 AgentResponse。

九丘教育官方博客 1475

Kafka 生产者 Producer 原理及重要参数

《深入理解kafka:核心设计与实践原理》笔记 ​ 一、整体架构   消息在真正发往 Kafka 之前,有可能需要经过 拦截器(Interceptor)、序列化器(Serializer)和分区器(Partitioner)等一系列作用,下面先来看一下生产者客户端的整体架构。   拦截器(Interceptor):Kafka 一共有两种拦截器:生产者拦截器和消费者拦截器。生产者拦截器既可以用来在消息发送前做一些准备工作,比如按照某个规则过滤不符合要求的消息、修改消息的内容等,也可以用来在发送回调逻辑前做一些定

qq_44503377的博客 2507

Multisim的探针(Probe)及数字电路的一些调试技巧的应用

Multisim的探针(Probe)及数字电路的一些调试技巧的应用 --EE Bang   By  WRS 上图为555方波发生器,根据R1,R2,C2参数的配置可产生频率为46.3KHZ,占空比50%的方波信号,如果用示波器查看波形参数的话需要用两个坐标轴做差,操作不便,另外如果要修改电路将上述电阻换成滑动变阻器的话,使其产生可变频率

Agent Christmas的博客 3万+

Allegro如何用自带的功能将线段变成铜皮操作指导

在做PCB设计的时候,有时根据设计需要将线段变成铜皮,可以借助辅助工具来实现这一操作,但是Allegro自身也自带这个功能,如下图。勾选Delete original objects。如何用自带的功能将线段变成铜皮操作指导。勾选Convert to shape,需要把这段走线变成铜皮。

weixin_54787054的博客 2946

Java NIO 之 ByteBuffer

抽象类ByteBuffer ByteBuffer的继承关系 父类 子类 目前,大概有5个实现类 ByteBuffer底层,主要依赖? 顾名思义,从ByteBuffer的名称来看,这个缓冲区针对的是字节类型的缓冲区, 从源码中,也可以查询到, 就是字节数组 ByteBuffer的主要api 我这里仅仅...

weixin_34357962的博客 91

区块链技术与应用 【全国职业院校技能大赛国赛题目解析】Caliper从0到使用

技能大赛样题解析,caliper题目从0到使用

weixin_52865146的博客 2076

【源码解析】Java NIO 包中的 ByteBuffer

上一篇文章我们介绍了最底层的 Buffer,那么这篇文章就要介绍下 Buffer 的【源码解析】Java NIO 包中的 Buffer上面就是 Buffer 的继承结构,当然 Buffer 的子类肯定不会只有这么点,比如下面的图:只不过上面图中就给了几个基本 Buffer 的实现类,可以看到几个重要的实现类都是ByteBuffer的子类,这几个实现类也是我们要介绍的重点,只不过这篇文章我们先介绍 ByteBuffer。

Jwasx的博客 1493

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【Java源码阅读系列44】深度解读Java NIO ByteBuffer 源码

Java NIO(New Input/Output)中的 ByteBuffer 是 Buffer 抽象类的具体子类,专门用于处理字节数据的高效读写。作为 NIO 的核心组件,ByteBuffer 支持堆内存(Heap)和直接内存(Direct)两种存储方式,广泛应用于网络通信、文件 IO 等场景。本文将结合源码,深入解析 ByteBuffer 的核心机制、关键方法及设计模式的应用。

专注Java和MySQL领域知识分享 1037

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Java NIO 总结: ByteBuffer类介绍

ByteBuffer是Java NIO包中的一个类,它实现了Buffer接口,是处理字节数据的基础类。ByteBuffer类提供了多种方法,用于读取和写入字节数据,以及管理缓冲区的状态。ByteBuffer类支持多种数据类型,包括字节、字符、短整型、整型、长整型、浮点型和双精度浮点型等。ByteBuffer内部使用一个字节数组(byte[])来存储数据,通过操作数组中的索引位置来实现数据的读写。ByteBuffer类提供了多种方法,用于读取和写入字节数据,以及管理缓冲区的状态。

码到三十五 1653

深入理解 Java NIO:ByteBuffer和MappedByteBuffer的特性与使用

在深入学习 RocketMQ 这款高性能消息队列框架的源码时,发现ByteBuffer和在 RocketMQ 这样的高性能消息队列框架中扮演了关键角色,其核心部分广泛使用了这两种缓冲区,以实现高效的数据存储和异步刷盘操作。接下来就深入学习ByteBuffer 和 MappedByteBuffer 的工作原理、优势特点,以便能运用到实际业务中。

RemainderTime 2173

java.nio.ByteBuffer详解

一、ByteBuffer原理 关于这个类,其实他有两个子类:一个是HeapByteBuffer和DirectByteBuffer关于这两个类的区别很好理解: DirectByteBuffer不是分配在堆上的,它不被GC直接管理(但Direct Buffer的JAVA对象是归GC管理的,只要GC回收了它的JAVA对象,操作系统才会释放Direct Buffer所申请的空间),它似乎给人感觉是“内...

tyrroo的博客 3103

java nio ByteBuffer源码分析

目录 简介 字段hb,offset,isReadOnly,2个构造函数 方法allocateDirect,allocate,2个wrap,slice,duplicate,asReadOnlyBuffer 方法4个get,5个put 方法array,arrayOffset,compact,isDirect,toString,hashCode,2个equals,compareTo 字段bigEndian,nativeByteOrder,方法order,_get,_put 方法getXXX,putX

今天吃了吗的博客 946

NIO ByteBuffer 总结(源码)

读模式 → 写模式(position=0,limit=capacity,数据未删除)。:写模式 → 读模式(limit=position,position=0)。:将未读数据复制到缓冲区头部,position设置为剩余数据末尾,继续写入。应用于通道(Channel)的I/O操作。:重置position为0,用于重新读取数据。:相对位置操作(自动移动position)。:绝对位置操作(不移动position)。是 Java NIO 中一个核心类,

weixin_43567035的博客 782

Netty 中的 ByteBuf 是什么,它和 Java NIO 的 ByteBuffer 有什么区别?

作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。

smart_an的专栏 1395

Java NIO之常用缓冲区ByteBuffer详解

定义: ByteBuffer是Buffer的实现类之一,是一个通用的缓冲区,功能要比其他缓冲区子类多。支持直接内存。是一个抽象类。子类实现是HeapByteBuffer(非直接缓冲区子类),DirectByteBuffer(直接缓冲区子类)。 看此文前建议看看: 关于Buffer可以查看 Java NIO学习篇之缓冲区Buffer详解 直接缓冲区: 以上是书《深入理解Java虚拟机》对直接内存的描述。简单来说直接内存不是JVM内存,而是计算机真正的物理内存。 我们IO中有个步骤是: 读:把内核缓冲区

lixinkuan的博客 1699

java.nio.ByteBuffer的 capacity, limit, position, mark

这四个属性定义在ByteBuffer的父类 java.nio.Buffer中。mark()方法不是返回mark属性的值, 而是设置。ByteBuffer的两个静态工厂方法。

kfepiza的博客 1753

java nio缓冲区源码,java.nio.ByteBuffer源码

所属包package java.nio;继承与实现关系public abstract class ByteBufferextends Bufferimplements Comparable属性//堆缓冲数组final byte[] hb;//字节数组偏移量final int offset;//堆缓冲是否可读boolean isReadOnly;构造器/*** 创建一个带有临时备忘标记变量、读写的开...

weixin_42444815的博客 209

区别NIO的ByteBuffer的get()与get(index)方法

先啰嗦一点废话,之前代码遇到错误,第一时间去百度,这次选择了阅读源码。然后真的是茅塞顿开,理解的更加深刻透彻,也节约了时间。然后考虑到源码都是英文的,可能阅读有困难,这时候就要推荐一个插件了==> Translation 背景 是在了解NIO的字符集Charset时遇到的问题。代码如下: @Test public void CharacterEncodingTest() thr...

litblue'blog 4763
上一篇: JAVA面试题 StringBuffer和StringBuilder的区别,从源码角度分析?
下一篇: 深入理解Java虚拟机笔记---底层原理分析与性能优化
程序员杨过
博客等级 码龄7年 13粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值