Java NIO笔记(二):NIO Buffer(缓冲区)之基础

《Java NIO》:Channel and Buffer (通道和缓冲区) 《Java NIO》:Channel and Buffer (通道和缓冲区)从今天开始,自己将会了解下Java NIO的相关知识,以及会看下相关的类库源码。和往常自己学习新知识之前,自己都会阅读网上的一些博文和资料,以使自己对这一块的知识有一个大致的了解,然后再按照自己感兴趣的点来研究一点点知识。关于Java NIO这一块的知识,也是如此。关于Java NIO涉及到三个重要的概念:1、Chan 阅读详情

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

缓冲区是包在一个对象内的基础数据的数组,Buffer类相比一般简单数组而言其优点是将数据的内容和相关信息放在一个对象里面,这个对象提供了处理缓冲区数据的丰富的API。

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

属性描述
Capacity容量,即可以容纳的最大数据量;在缓冲区创建时被设定并且不能改变
Limit上界,缓冲区中当前数据量
Position位置,下一个要被读或写的元素的索引
Mark标记,调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置即position=mark







一、创建缓冲区

        所有的缓冲区类都不能直接使用new关键字实例化,它们都是抽象类,但是它们都有一个用于创建相应实例的静态工厂方法,以ByteBuffer类为例子:

		//创建一个容量为10的byte缓冲区
		ByteBuffer buff = ByteBuffer.allocate(10);

上面代码将会从堆空间中分配一个容量大小为10的byte数组作为缓冲区的byte数据存储器。对于其他缓冲区类上面方式也适用,如创建容量为10的CharBuffer:

		//创建一个容量为10的char缓冲区
		CharBuffer buff = CharBuffer.allocate(10);

        如果想用一个指定大小的数组作为缓冲区的数据的存储器,可以使用wrap()方法:

		//使用一个指定数组作为缓冲区的存储器
		byte[] bytes = new byte[10];
		ByteBuffer buff = ByteBuffer.wrap(bytes);
上面代码中缓冲区的数据会存放在bytes数组中,bytes数组或buff缓冲区任何一方中数据的改动都会影响另一方。还可以创建指定初始位置(position)和上界(limit)的缓冲区:

		//使用一个指定数组作为缓冲区的存储器
		//并创建一个position=3,limit=8,capacity=10的缓冲区
		byte[] bytes = new byte[10];
		ByteBuffer buff = ByteBuffer.wrap(bytes, 3, 8);
下图是新创建的一个容量为10的字节缓冲区的内存图:


二、操作缓冲区

1、存取(Buffer.get() & Buffer.put())

        使用get()从缓冲区中取数据,使用put()向缓冲区中存数据。

		// 创建一个容量为10的byte数据缓冲区
		ByteBuffer buff = ByteBuffer.allocate(10);
		// 存入4次数据
		buff.put((byte) 'A');
		buff.put((byte) 'B');
		buff.put((byte) 'C');
		buff.put((byte) 'D');
		// 翻转缓冲区
		buff.flip();
		// 读取2次数据
		System.out.println((char)buff.get());
		System.out.println((char)buff.get());

        上面有提过缓冲区四个属性值一定遵循capacity>=limit>=position>=mark>=0,put()时,若position超过limit则会抛出BufferOverflowException;get()时,若position超过limit则会抛出BufferUnderflowException。

        buff.flip()是将缓冲区翻转,翻转将在下面来说。

调用put()或get()时,每调用一次position的值会加1,指示下次存或取开始的位置;

上面代码put()四次后的缓冲区内存示意图:


上面代码执行buff.flip()将缓冲区翻转后的内存示意图:


上面代码执两次get()后的缓冲区内存示意图:

        再向Buffer中读写数据时有2个方法也非常有用:

Buffer.remaining():返回从当前位置到上界的数据元素数量;

Buffer.hasRemaining():告诉我们从当前位置到上界是否有数据元素;

2、翻转(Buffer.flip())

        翻转就是将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态,使用flip()方式实现翻转。Buffer.flip()的源码如下:

	public final Buffer flip() {
		limit = position;
		position = 0;
		mark = -1;
		return this;
	}
相信看到了实现的源码应该就会清楚flip()的作用了。rewind()方法与flip()很相似,区别在于rewind()不会影响limit,而flip()会重设limit属性值,Buffer.rewind()的源码如下:

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

3、压缩(Buffer.compact())

        压缩就是将已读取了的数据丢弃,保留未读取的数据并将保留的数据重新填充到缓冲区的顶部,然后继续向缓冲区写入数据。

		// 创建一个容量为10的byte数据缓冲区
		ByteBuffer buff = ByteBuffer.allocate(10);
		// 填充缓冲区
		buff.put((byte)'A');
		buff.put((byte)'B');
		buff.put((byte)'C');
		buff.put((byte)'D');
		System.out.println("first put : " + new String(buff.array()));
		//翻转
		buff.flip();
		//释放
		System.out.println((char)buff.get());
		System.out.println((char)buff.get());
		//压缩
		buff.compact();
		System.out.println("compact after get : " + new String(buff.array()));
		//继续填充
		buff.put((byte)'E');
		buff.put((byte)'F');
		//输出所有
		System.out.println("put after compact : " + new String(buff.array()));

以上代码打印结果:

first put : ABCD

A

B

compact after get : CDCD

put after compact : CDEF

控制台中输出内容中有正方形的乱码,是正常。因为字节缓冲区中没有赋值的内存块默认值是0,而Unicode编码中没有0编码,所以乱码。

4、标记(Buffer.mark())

        标记就是记住当前位置(使用mark()方法标记),之后可以将位置恢复到标记处(使用reset()方法恢复),mark()和reset()源码如下:

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

	public final Buffer reset() {
		int m = mark;
		if (m < 0)
			throw new InvalidMarkException();
		position = m;
		return this;
	}
5、比较两个缓冲区是否相等

        比较两个缓冲区是否相等有2种方法:equals(Object ob) 和compareTo(ByteBuffer that),这两个方法都是在Buffer的子类中实现的。

        equals比较的两个缓冲区中的每个值,所以允许不同的Buffer对象进行比较;compareTo有类型限制,ByteBuffer只能和ByteBuffer进行比较;比较两个缓冲区实际上是比较两个缓冲区中每个缓冲区position到limit之间(不包括limit)的缓冲值。如下图:

6、批量移动缓冲区的数据

        缓冲区的目的就是高效传输数据,高效传输数据就应杜绝一个一个的传输,所以Buffer API提供了相应的方法来进行批量移动。下面是个例子:

		byte[] bytes = "hello world!".getBytes();
		// 创建一个容量等bytes容量的byte数据缓冲区
		ByteBuffer buff = ByteBuffer.allocate(bytes.length);
		//将byte数据写入缓冲区,下面代码和buff.put(bytes)效果一致
		buff.put(bytes, 0, bytes.length);
		//翻转缓冲区
		buff.flip();
		//轮询判断是否有数据,有则将缓冲区的数据批量读到array中
		byte[] array = 	new byte[bytes.length];
		while(buff.hasRemaining()){
			buff.get(array, 0, buff.remaining());
		}
		//输出冲缓冲区读出来的数据
		System.out.println(new String(array));
以上面代码为例,

写数据到缓冲区时,若bytes.length > buff.capacity()则会抛出java.nio.BufferOverflowException;

从缓冲区中读数据时,若array.length < buff.limit()则会抛出java.lang.IndexOutOfBoundsException。

7、复制缓冲区

        复制一个与源缓冲区共享数据的缓冲区,各自管理自己的属性

  • asReadOnlyBuffer():复制一个只读缓冲区
  • duplicate():复制一个可读可写的缓冲区
  • slice():复制一个从源缓冲position到limit的新缓冲区

Windows下的Geant4安装教程 本教程将从0开始展示在Windows下如何安装Geant4,包括各种辅助工具(QT、Cmake、Visual Studio)的下载安装,环境变量的配置,以及example的生成等。 阅读详情

相关推荐

电机控制中ADC采样时序的优化策略与实践

本文深入探讨了电机控制中ADC采样时序的优化策略与实践,重点分析了BLDC和FOC控制方案中的核心挑战与解决方案。通过硬件布局优化、软件滤波技术及动态时序补偿等方法,有效提升电流采样精度和系统稳定性,为电机控制系统的性能优化提供实用指导。

weixin_42519985的博客 386

NIO Buffer 实现原理

目前很多高性能的Java RPC框架都是基于Netty实现的,而Netty的设计原理又离不开Java NIO。本篇笔记是对NIO核心三件套:缓冲区(Buffer)、选择器 (Selector)和通道(Channel),其中之一的实现原理的学习总结。

兴趣使然的草帽路飞 1万+

ESP8266连接阿里云(STM32)

一、概述 之前通过串口调试助手+ESP8266已经连接上阿里云了 ESP8266连接阿里云(串口调试助手) 这次我们使用STM32+ESP8266来接入阿里云,其实本质上就是STM32和ESP8266进行串口通信,相当于使用STM32代替之前使用的串口调试助手来发送AT指令。只是发送的字符串数据可能有些细节需要注意一下。 二、保存连接的AT指令 定义几个字符串数据保存需要发送的AT指令 //注意: //末尾记得加\r\n //字符...

xyx0610的博客 4万+

buffer

类进行数据读写操作时,需要确保缓冲区有足够的容量来存储数据,否则可能会发生缓冲区溢出的情况。另外,需要正确处理缓冲区的位置和限制位置,以避免数据不完整或丢失的情况。提供了一组读写方法,用于向缓冲区中写入数据或从缓冲区中读取数据。它也提供了一些属性和方法,用于管理缓冲区的状态、容量和位置等。是一个抽象的数据缓冲区,它可以存储不同类型的数据,包括字节、字符、整数、浮点数等。在这个示例中,我们首先创建了一个大小为 1024 的字节缓冲区,并使用。方法将缓冲区切换到写模式,以便我们可以继续向缓冲区中写入数据。

雅文科技的博客 501

Python 逆向解析知乎盐选反爬字体,实现内容精准还原

本文详细解析了知乎盐选内容的反爬字体机制,并提供了使用Python逆向解析WOFF字体文件的完整方案。通过fontTools库构建解码字典,实现乱码文本的精准还原,帮助开发者应对动态字体策略,同时强调法律与道德风险。

weixin_29268385的博客 1295

Python 使用Pygame库实现足球游戏:创建一个球员和一个足球,并使玩家能够控制球员的移动。游戏将包括碰撞检测、简单的物理模拟,以及基本的用户输入处理

本文将介绍如何使用Python和Pygame库创建一个简单的足球游戏。我们将搭建一个基本的游戏环境,创建一个球员和一个足球,并使玩家能够控制球员的移动。游戏将包括碰撞检测、简单的物理模拟,以及基本的用户输入处理。这个简单的足球游戏展示了Pygame的一些基本功能。虽然这是一个简单的游戏,但它包含了创建游戏循环、用户输入处理、物理模拟、碰撞检测等重要概念。

程序熊的博客 743

NIO--Buffer

Buffer 缓冲区基础 概念上,缓冲区是包在一个对象内的基本数据元素数组。Buffer类相比一个简单数组的优点是它将关于数据的数据内容和信息包含在一个单一的对象中。Buffer类以及它专有的子类定义了一个用于处理数据缓冲区的API。 属性 所有的缓冲区都具有四个属性来提供关于其所包含的数据元素的信息。它们是: 容量(Capacity) 缓冲区能够容纳的数据元素的最大数量。这一容量...

demon7552003的小本本 511

基于Matlab与Bladed联合仿真的交互软件设计

基于Matlab与Bladed的交互软件设计

weixin_45014222的博客 815

ByteBuffer remaining 简介

现在我们获得一个buffer,即缓冲区。里面存在len长度的可用数据。我们要做的就是根据自己的协议结构将这个buffer转化为遵循我们自己的协议的packet。进而交由后面的业务逻辑代码处理。 此时我们定义自己的通信协议一个byte的包头,用于数据吧合法性验证,两byte数据包长(一般用4byte,即一个int),剩下内容为可变长度的数据包体。现在我们拿到buffer,这时候就有分包(粘包)

guomeijuan916的专栏 3万+

linux 内核vxlan收发包流程

1.vxlan口收包处理流程 前面几章详细介绍了vxlan接口的使用,而且已经知道vxlan是 MAC IN UDP中的封装,因此,在解封装之前,一切按照原有流程走,在此复习一下内核收发包流程(驱动层的数据处理这次不再解析,直接从__netif_receive_skb_core开始) #物理网卡处理中断,触发softirq i40e_intr └─napi_schedule_irqoff #i40e softirq把包放到per cpu backlog,触发softirq i40e_napi_p

魏言华的博客 3825

大模型长对话中上下文无法承载全部历史,如何压缩或提取重点

如果说截断和滑动窗口是“硬性”压缩,那摘要生成技术就显得“软”多了,也更接近于智能化的解决方案。它的思路是:不直接丢弃历史,而是通过自然语言处理(NLP)技术,把冗长的对话记录浓缩成一段简短的摘要,保留核心信息。这样既能大幅减少token数量,又不至于丢失关键内容。这种方法通常会借助预训练模型,比如BART或T5,它们擅长从长文本中提取重点内容。

大模型大数据攻城狮的专栏 1586

java bytebuffer 大小_Java - ByteBuffer.remaining()问题

简介:我有一个ByteBuffer,我在其中提取一些数据。之后,我想通过Socket发送这些数据。所以,我写了这样的代码:private static void serialize(ByteBuffer buffer, EmployeeData emp, CharsetEncoder encoder){// idbuffer.putInt(emp.getId());CharBuffer nameB...

weixin_29863361的博客 1503

Camunda 7.x 系列【62】启动流程实例源码解析

为了更好的了解Camunda,接下来我们简单分析下启动流程实例相关源码

记录知识、锤炼自我 1171

Java 入门指南:Java NIO —— Buffer(缓冲区)

在 NIO(New Input/Output)模型中,Buffer 是一个重要的概念,与数据打交道,用于在内存中存储数据。通过 Channel 将数据传输到 Buffer 缓冲区中,并在缓冲区内进行数据的读写操作。 Buffer 本质上是一个数组,可以存储多个相同类型的基本数据类型,如 byte、short、int、long、float、double 等。Buffer 封装了内部的数组,并提供了一些操作该数组的方法。

热带鱼的技术博客 2258

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Java NIO的Buffer缓冲区和Channel通道详细总结

NIO 主要有在 NIO 中,并不是以流的方式来处理数据的,而是以 buffer 缓冲区和 Channel 通道来处理数据的。可以简单理解为把Channel通道比作 铁路,buffer缓冲区比作成火车(运载着货物),而NIO就是通过来实现数据的处理。Buffer 是缓冲区的抽象类,ByteBuffer 是(在通道中读写字节数据):拿到一个缓冲区我们往往会做什么?很简单,就是。所以,缓冲区的核心方法就是 put 和 get:Buffer 类维护了 4 个核心变量来提供。get()put()现在,怎么拿呀。

qq_62636650的博客 1564

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

java笔记--NIO基础--Buffer缓冲区

注意,执行完写操作后想要进行读之前,要执行filp()方法翻转:limit = position;| 使用 | put/get/channel 读写 | 不走 JVM 堆,效率高 || 释放 | 依赖 GC 和 Cleaner | 不可手动释放,不能频繁创建 || native 分配堆外内存 |

lxq6966892的博客 1246

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Java NIO之缓冲区Buffer分析

目录 Buffer介绍 ByteBuffer介绍 ByteBuffer案例 总结 Buffer介绍 1.Buffer简介       缓冲区(Buffer)是中NIO中基础的内容,存在于包java.nio下面.一个Buffer对象可以看做是一个存储数据的容器,数据被存储到这里后可以进行检索。缓冲区工作与通道关联,我们不与通道直接进行交互,而是通过缓冲区将数据传送到通道里,或者从通道获...

梦悠哉的博客 1740

Java NIO ———— Buffer 缓冲区详解

引言 缓冲区是一个用于特定基本类型的容器。由java.nio 包定义,所有缓冲区都是 Buffer 抽象类的子类。 Java NIO 中的 Buffer ,主要用于与NIO 通道进行交互。数据从通道存入缓冲区,从缓冲区取出到通道中。 一、创建缓冲区 缓冲区的本质是数组,用于存储不同类型的数据,根据数据类型(boolean 除外),提供了相应类型的缓冲区,如ByteBuffer、In...

Morty的技术乐园 2450

Java NIO——缓冲区Buffer

目录什么是Java NIO 什么是Java NIO Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。 Java NIO系统的核心在于:通道(Channel)和缓冲区(Buffer)。通道表示打开到 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO 系统,需要获取用于连接 I

guochaoHNU的博客 1127

《Java源码解析》NIO中Buffer缓冲区的实现

Buffer 缓冲区Java的NIO中Buffer至关重要:buffer是读写的中介,主要和NIO的通道交互。数据是通过通道读入缓冲区和从缓冲区写入通道的。其实缓冲区buffer的本质就是一块可以读写的内存块。这块内存块被包装成NIO的Buffer对象,并提供了一组方法方便读写。3.1 Buffer的基本用法:使用Buffer读写数据一般是下面步骤: 1. 写入数据到Buffer 2. 调用fl

惜暮 2480

JAVA NIO(二)NIO之缓冲区(Buffer)详解

缓冲区在java NIO中负责数据的存取。缓冲区就是数组,用于存储不同数据类型的数据

zjx2016的博客 775

Java-NIO之Buffer(缓冲区)

Buffer 是什么 Buffer(缓冲区)本质上是一个由基本类型数组构成的容器。 我们先看看Buffer类的基本构成: public abstract class Buffer { // Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private in

HongYu012的博客 1038

Java NIO三大核心之缓冲区Buffer概述

定义 缓冲区Buffer在java nio中负责数据的存储,缓冲区就是数组,用于存储不同类型数据的数组。 jdk为java七大基本类型数据都准备了响应的缓冲区(boolean值除外): ByteBuffer CharBuffer ShortBuffer IntegerBuffer LongBuffer FloatBuffer DoubleBuffer 上述缓冲区除了ByteBuffer的 功能稍微多点外,因为ByteBuffer是通用的,所以功能会比较多。其他6种的使用方式几乎是一致的。 /* * B

lixinkuan的博客 3770

Java NIO之缓冲区Buffer

NIO与IO的区别 由面向存取数据的载体、是否阻塞等可以分为以下三点不同: 面向流: 数据像水流一样传输,并且,要么输入要么输出,流是单向的。所以以前的IO流都有输入流,输出流。 面向缓冲区: NIO会在程序与文件(磁盘、网络)之间建立一个通道用于连接,然后通过缓冲区进行数据存取,通过通道进行连接传递。 阻塞IO和非阻塞IO、选择器主要是针对网络编程而言的。 通道( Ch...

ystyaoshengting的专栏 589

Java NIO系列3:缓冲区

前言一直想把NIO系列的文章更新下去,只不过发现在入职支付宝后工作实在是忙,所以一直拖到现在。直接从一个学生过狗成为一名加班狗,好吧,这就是互联网公司的现状吧,但是每天都是充实的,而且发现其他的员工也基本非常乐意加班,难道这就是阿里的文化熏陶?!废话不多说,还是进入今天的正题,在前面的文章中,我们已经对Java的NIO有了一个粗浅的认识——主要之为了支持非阻塞I/O的操作,之前的BIO则是阻塞的。因

rhwayfun专栏 5620

NIO学习笔记——缓冲区(Buffer)详解

缓冲区是包在一个对象内的基本数据元素数组,Buffer类相比一个简单的数组的优点是它将关于数据的数据内容和信息包含在一个单一的对象中。Buffer的属性容量(capacity):缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,并且永远不能被改变 上界(limit):缓冲区的第一个不能被读或写的元素。或者说,缓冲区中现存元素的计数 位置(position):下一个要被读或写的元素

路漫漫,水迢迢 8463
上一篇: Java NIO笔记(一):NIO介绍
下一篇: Java NIO笔记(三):NIO Buffer(缓冲区)之进阶
xlight2023
博客等级 码龄15年 236粉丝 32原创
评论 9
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值