JAVA NIO(二) Buffer和Channel

news2024/11/27 8:41:08

一,基本使用


1, 一个Socket连接使用一个Channel来表示,以前直接操作Socket文件描述符来对读写缓冲区操作,比如读数据到用户空间的一个byte数组,NIO中Channel对这个过程作了封装,其中用户空间的byte数组就类比Buffer。
2,Buffer用于和Channel进行交互。
  • Channel中的数据总是要先写入到Buffer,或从Buffer读取;
  • Buffer中的数据可以来源于Channel,也可以直接get和put;
3,Buffer本质上是一块可以读写的内存,被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
4,使用Buffer读写数据一般遵循以下四个步骤:
  1. 写入数据到Buffer;
  2. 调用flip()方法,切换写模式到读模式;
  3. 从Buffer中读取数据;
  4. 调用clear()方法或者compact()方法,清空缓冲区;
示例:
RandomAccessFile aFile = new RandomAccessFile("/Users/jiec/Documents/testdata/data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

ByteBuffer buf = ByteBuffer.allocate(48);

// 数据写入buffer
int bytesRead = inChannel.read(buf); 
while (bytesRead != -1) {

    // buffer转为读模式
    buf.flip();

    while (buf.hasRemaining()) {
        // 每次读一个byte
        System.out.print((char) buf.get());
    }

  // make buffer ready for writing
    buf.clear();

    bytesRead = inChannel.read(buf);
}
aFile.close();

二,Channel的类型


Java NIO的通道操作类似BIO的流,但又有些不同:
  1. 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的;
  2. 通道可以异步地读写;
  3. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入;
Java NIO中最重要的通道的实现:
  • FileChannel:从文件中读写数据;
  • DatagramChannel:能通过UDP读写网络中的数据;
  • SocketChannel:能通过TCP读写网络中的数据;
  • ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel;

三,Buffer的类型


Java NIO 有以下Buffer类型
  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer
代表了不同的数据类型。换句话说,就是可以通过byte、char,short,int,long,float 或 double类型来操作缓冲区中的字节。

四,Buffer的属性capacity、position、limit


position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity含义总是一样的。
capacity
内存块的容量。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。
position
写数据时,初始position值为0,最大可为capacity–1。
读数据时,当Buffer从写模式切换到读模式,position会被重置为0。
limit
写模式,limit表示最多能往Buffer里写多少数据。 写模式下limit等于capacity。
读模式, limit表示最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。

五,Buffer的分配


每一个Buffer类都有一个allocate方法。
分配48字节ByteBuffer:
ByteBuffer buf = ByteBuffer.allocate(48);
分配1024个字符的CharBuffer:
CharBuffer buf = CharBuffer.allocate(1024);
对于ByteBuffer,看下源码:
public static ByteBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    return new HeapByteBuffer(capacity, capacity);
}
创建的是HeapByteBuffer,这是个位于堆区的对象,注意和MappedByteBuffer区分,后者实际存储在直接内存。
ByteBuffer分为两种,一种是堆内内存,另外一种是堆外内存。
堆外内存:使用内存映射,直接在 JVM 之外分配虚拟内存地址空间,Java 中使用 DirectByteBuffer 来实现,也就是堆外内存。
堆内内存:是在 JVM 堆上实现,Java 中使用 HeapByteBuffer 来实现,也就是堆内内存。

六,向Buffer中写数据


写数据到Buffer有两种方式:
  1. 从Channel写到Buffer;
  2. 通过Buffer的put()方法写到Buffer里;
Channel -> Buffer的例子
int bytesRead = inChannel.read(buf); //read into buffer.

通过put方法写Buffer的例子:

buf.put(127);

七,从Buffer中读数据


从Buffer中读取数据有两种方式:
  1. 从Buffer读取数据到Channel。
  2. 使用get()方法从Buffer中读取数据。
Buffer -> Channel的例子
int bytesWritten = inChannel.write(buf);

通过get方法读Buffer的例子:

byte aByte = buf.get();

八,Buffer的一些方法使用


1,flip()
将Buffer从写模式切换到读模式。
调用flip()方法会将position设回0,并将limit设置成之前position的值。换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等,现在能读取多少个byte、char等。
--------------------------------------------------------------------------------------------------------------------------------
2,rewind()
Buffer.rewind()将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)。
--------------------------------------------------------------------------------------------------------------------------------
3,clear()和compact()
一旦读完Buffer中的数据,需要让Buffer准备好再次被写入,可以通过clear()或compact()方法来完成。
clear()方法:position=0,limit=capacity。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据,写入时老数据会被覆盖
compact()方法:将所有未读的数据拷贝到Buffer起始处,然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。Buffer写数据时,不会覆盖未读的数据
--------------------------------------------------------------------------------------------------------------------------------
4,mark()与reset()方法
通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。例如:
buffer.mark();
//call buffer.get() a couple of times, e.g. during parsing.
buffer.reset();  //set position back to mark.
--------------------------------------------------------------------------------------------------------------------------------
5,equals()与compareTo()方法
可以使用equals()和compareTo()方法比较两个Buffer。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1848749.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电商数据:准确性与覆盖率的关键意义

在当今的电商环境下&#xff0c;以电商数据为驱动&#xff0c;品牌能够开展诸多与渠道相关的工作&#xff0c;像是电商数据监测、数据分析以及低价治理等。然而&#xff0c;所有这些工作的首要前提便是数据的准确性必须达到较高水平。倘若准确性无法得到有效保障&#xff0c;那…

C语言 | Leetcode C语言题解之第172题阶乘后的零

题目&#xff1a; 题解&#xff1a; int trailingZeroes(int n) {int ans 0;while (n) {n / 5;ans n;}return ans; }

【STM32】时钟树系统

1.时钟树简介 1.1五个时钟源 LSI是低速内部时钟&#xff0c;RC振荡器&#xff0c;频率为32kHz左右。供独立看门狗和自动唤醒单元使用。 LSE是低速外部时钟&#xff0c;接频率为32.768kHz的石英晶体。这个主要是RTC的时钟源。 HSE是高速外部时钟&#xff0c;可接石英*/陶瓷谐振…

el-input-number 限制输入正整数

vue 页面 限制输入最小值为0 :min"0" <el-input-number v-model"scope.row.num" change"handleNumChange(scope)" keydown.enter.prevent style"width: 200px; " :min"0" />methods 里面限制输入的数字不为小数 使…

DPDK与传统收发报文的区别

1.去除中断 传统的收发报文方式都必须采用硬中断来做通讯&#xff0c;每次硬中断大约消耗100微秒&#xff0c;这还不算因为终止上下文所带来的Cache Miss。 DPDK采用轮询模式驱动(PMD)。 PMD由用户空间的特定的驱动程序提供的API组成&#xff0c;用于对设备和它们相应的…

Swoole_loader扩展安装图文教程 Swoole扩展文件下载

Swoole_loader扩展安装图文教程 Swoole扩展文件下载 安装和配置Swoole Loader 1 - 下载Swoole Loader 请下载兼容PHP7.2和非线程安全的Swoole Loader扩展&#xff0c;点击下载适配环境的扩展文件 2 - 安装Swoole Loader 将刚才下载的Swoole Loader扩展文件&#xff08;swo…

Redis—List数据类型及其常用命令详解

文章目录 一、Redis概述List类型1 LPUSH:将一个或多个值插入到列表头部2 RPUSH:将一个或多个值插入到列表尾部3 LPOP:从列表头部弹出并移除一个或多个元素4 RPOP&#xff1a;从列表尾部弹出一个或多个元素5 LLEN:获取 Redis 列表的长度6 LRANGE:获取 Redis 列表中指定范围内的元…

SpringCloud 基于Nacos和Eureka 实现双注册双订阅

一、使用场景/原因 过渡期迁移: 当系统从一个服务注册中心迁移到另一个时&#xff0c;例如从 Eureka 迁移到 Nacos&#xff0c;可以在过渡期内同时使用两个注册中心&#xff0c;确保服务平稳迁移&#xff0c;逐步过渡&#xff0c;避免一次性切换带来的风险。 兼容性考虑: 不同的…

http/2 二进制分帧层 (Binary Framing Layer)讲解

文章目录 二进制帧HTTP/2 中的帧、消息和流1. 帧&#xff08;Frame&#xff09;2. 消息&#xff08;Message&#xff09;3. 流&#xff08;Stream&#xff09;总结示例&#xff1a; 二进制帧结构1.帧头部结构2.帧负载数据 请求和响应多路复用 链接参考&#xff1a;https://web.…

C#修改 EXE 文件图标和 winForm 窗口图标

修改 EXE 文件图标 1.准备好图片&#xff0c;转换为 Icon 图片&#xff1b; 2.右键工程&#xff0c;选择属性&#xff1b; 3.选择 Icon 图标即可&#xff1b; 4.重新生成可执行文件&#xff0c;查看。 修改 winForm 窗口图标 1.选中 winForm &#xff0c;查看属性&#x…

天马学航——智慧教务系统(移动端)开发日志三

天马学航——智慧教务系统(移动端)开发日志三 日志摘要&#xff1a;更新了学生选课模块、我的课程模块以及退课的功能&#xff0c;优化了后端数据库的缓存 1、学生选课模块 学生选课模块主要实现&#xff0c;学生根据需求进行选课操作&#xff0c;通过后端查询到所有教师的课…

mysql 主从延迟

mysql 主从延迟 精华推荐 | 【MySQL技术专题】「主从同步架构」全面详细透析MySQL的三种主从复制&#xff08;Replication&#xff09;机制的原理和实战开发&#xff08;原理实战&#xff09; https://blog.csdn.net/l569590478/article/details/128329929 mysql主从之多线程复…

Nuxt 3 路由系统详解:配置与实践指南

title: Nuxt 3 路由系统详解&#xff1a;配置与实践指南 date: 2024/6/21 updated: 2024/6/21 author: cmdragon excerpt: 摘要&#xff1a;本文是一份关于Nuxt 3路由系统的详尽指南。它从介绍Nuxt 3的基本概念开始&#xff0c;包括Nuxt 3与Nuxt 2的区别和选择Nuxt 3的理由。…

创建OpenWRT虚拟机

环境&#xff1a;Ubuntu 2204&#xff0c;VM VirtualBox 7.0.18 安装必备软件包&#xff1a; sudo apt update sudo apt install subversion automake make cmake uuid-dev gcc vim build-essential clang flex bison g gawk gcc-multilib g-multilib gettext git libncurses…

供应链投毒预警 | utilitytool系列Py包开展XenoRAT远控木马投毒

概述 上周&#xff08;2024年6月14号&#xff09;&#xff0c;悬镜供应链安全情报中心在Pypi官方仓库&#xff08;https://pypi.org/&#xff09;中捕获2起针对Windows系统的Python包投毒事件&#xff0c;涉及Python组件包utilitytool及utilitytools&#xff0c;投毒者&#x…

C++开发基础之频繁使用`std::endl`可能导致性能问题

前言 你是否曾经注意过这个问题&#xff0c;频繁使用std::endl可能导致性能问题。在C开发中&#xff0c;许多开发者习惯于使用std::endl来换行输出并刷新缓冲区。然而&#xff0c;这种习惯性操作可能会在高频率输出场景中带来显著的性能瓶颈。接下来&#xff0c;我们将深入探讨…

2.XSS-存储型

储存型XSS 或持久型 XSS 交互的数据会被存在在数据库里面,永久性存储,具有很强的稳定性。 在留言板里面进行测试一下是否有做过滤 "<>?&66666点击提交 查看元素代码&#xff0c;已经提交完成&#xff0c;并且没有做任何的过滤措施 接下来写一个javascrip…

由于没有远程桌面授权服务器怎么办?

在现代的工作环境中&#xff0c;远程访问和远程桌面控制已经成为一项日益重要的需求。随着企业和组织的扩张&#xff0c;人们经常需要在不同的地点之间共享文件和应用程序。由于缺乏远程桌面授权服务器&#xff0c;这一过程可能会变得困难和不安全。 远程桌面授权服务器是一种…

MGV电源维修KUKA机器人电源模块PH2003-4840

MGV电源维修 库卡电源模块维修 机器人电源模块维修 库卡控制器维修 KUKA电源维修 库卡机器人KUKA主机维修 KUKA驱动器模块维修 机械行业维修&#xff1a;西门子系统、法那克系统、沙迪克、FIDIA、天田、阿玛达、友嘉、大宇系统&#xff1b;数控冲床、剪板机、折弯机等品牌数控…

gbase8s之Encoding or code set not supported

如图发生以下错误&#xff1a; 解决办法&#xff1a;在url里加上ifx_use_strenctrue 就可以了 参数解释&#xff1a;