详细了解JAVA NIO之Buffer(缓冲区)
作者:rickiyang 发布时间:2022-08-18 00:59:28
当我们需要与 NIO Channel 进行交互时, 我们就需要使用到 NIO Buffer, 即数据从 Buffer读取到 Channel 中, 并且从 Channel 中写入到 Buffer 中。缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
缓冲区基础
Buffer 类型有:
缓冲区是包在一个对象内的基础数据的数组,Buffer类相比一般简单数组而言其优点是将数据的内容和相关信息放在一个对象里面,这个对象提供了处理缓冲区数据的丰富的API。
所有缓冲区都有4个属性:capacity、limit、position、mark,并遵循:capacity>=limit>=position>=mark>=0,下面是对这4个属性的解释:
Capacity: 容量,即可以容纳的最大数据量;在缓冲区创建时被设定并且不能改变
Limit: 上界,缓冲区中当前数据量
Position: 位置,下一个要被读或写的元素的索引
Mark: 标记,调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置即position=mark
我们通过一个简单的操作流程来说明buffer的使用,下图是新创建的容量为10的缓冲区逻辑视图:
然后进行5次调用put:
buffer.put((byte)'A').put((byte)'B').put((byte)'C').put((byte)'D').put((byte)'E')
5次调用put之后的缓冲区为:
现在缓冲区满了,我们必须将其清空。我们想把这个缓冲区传递给一个通道,以使内容能被全部写出,但现在执行get()无疑会取出未定义的数据。我们必须将 posistion设为0,然后通道就会从正确的位置开始读了,但读到哪算读完了呢?这正是limit引入的原因,它指明缓冲区有效内容的未端。这个操作 在缓冲区中叫做翻转:buffer.flip()。
Buffer的基本用法
使用Buffer读写数据一般遵循以下四个步骤:
写入数据到Buffer
调用flip()方法
从Buffer中读取数据
调用clear()方法或者compact()方法
当向buffer写入数据时,buffer会记录下写了多少数据。
一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。
一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用clear()或compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。
下面我们看一段程序来看一下Buffer的基本用法:
public static void readFile(String fileName) {
RandomAccessFile aFile = null;
try {
//文件流
aFile = new RandomAccessFile(fileName, "rw");
//将文件输入到管道
FileChannel inChannel = aFile.getChannel();
//为buffer分配1024个字节大小的空间
ByteBuffer buf = ByteBuffer.allocate(1024);
//将buffer中的内容读取到管道中
int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {
//反转buffer,将写模式改为读模式
buf.flip();
while (buf.hasRemaining()) {
//获取buffer中的数据
System.out.print((char) buf.get());
}
//将上次分配的1024字节的内容清空,为下次接收做准备
buf.clear();
//管道重新读取buffer中的内容
bytesRead = inChannel.read(buf);
}
aFile.close();
} catch (Exception e) {
e.printStackTrace();
}
}
字节缓冲区
我们将进一步观察字节缓冲区。所有的基本数据类型都有相应的缓冲区类(布尔型除外),但字节缓冲区有自己的独特之处。字节是操作系统及其I/O设备使用的基本数据类型。当在JVM和操作系统间传递数据时,将其他的数据类型拆分成构成它们的字节是十分必要的。如我们在后面的章节中将要看到的那样,系统层次的I/O面向字节的性质可以在整个缓冲区的设计以及它们互相配合的服务中感受到。
直接缓冲区
我们知道操作系统是在内存中进行I/O操作,这些内存区域,就操作系统方面而言,是相连的字节序列。于是,毫无疑问,只有字节缓冲区有资格参与I/O操作。即操作系统会直接存取进程,那么我们现在在JVM中进行操作,java中的内存空间是由JVM直接进行管理,但是在JVM中,字节数组可能不会在内存中连续存储,或者无用存储单元收集可能随时对其进行移动,这就不能保证I/O操作的目标是连续的。
出于这一原因,引入了直接缓冲区的概念。直接缓冲区被用于与通道和固有I/O例程交互。它们通过使用固有代码来告知操作系统直接释放或填充内存区域,对用于通道直接或原始存取的内存区域中的字节元素的存储尽了最大的努力。
直接字节缓冲区通常是I/O操作最好的选择。在设计方面,它们支持JVM可用的最高效I/O机制。非直接字节缓冲区可以被传递给通道,但是这样可能导致性能损耗。通常非直接缓冲不可能成为一个本地I/O操作的目标。如果您向一个通道中传递一个非直接ByteBuffer对象用于写入,通道可能会在每次调用中隐含地进行下面的操作:
创建一个临时的直接ByteBuffer对象。
将非直接缓冲区的内容复制到临时缓冲中。
使用临时缓冲区执行低层次I/O操作。
临时缓冲区对象离开作用域,并最终成为被回收的无用数据。
视图缓冲区
就像我们已经讨论的那样,I/O基本上可以归结成组字节数据的四处传递。在进行大数据量的I/O操作时,很又可能你会使用各种ByteBuffer类去读取文件内容,接收来自网络连接的数据,等等。一旦数据到达了你的ByteBuffer,您就需要查看它以决定怎么做或者在将它发送出去之前对它进行一些操作。ByteBuffer类提供了丰富的API来创建视图缓冲区。
视图缓冲区通过已存在的缓冲区对象实例的工厂方法来创建。这种视图对象维护它自己的属性,容量,位置,上界和标记,但是和原来的缓冲区共享数据元素。但是ByteBuffer类允许创建视图来将byte型缓冲区字节数据映射为其它的原始数据类型。例如,asLongBuffer()函数创建一个将八个字节型数据当成一个long型数据来存取的视图缓冲区。
但是使用视图缓冲区的话,一旦ByteBuffer对于视图的维护对象产生非常规行的使用,那么对于工厂方法创建的缓冲区而言,asLongBuffer()函数就不在使用这个视窗,那么这个8字节的数据当成一个long类型的数据类型来存取的数据视图。
来源:https://www.cnblogs.com/rickiyang/p/11074243.html


猜你喜欢
- 注意我这里用的是官方最稳定的版本3.7.1,版本之间有个别命令是有差距的!1.zkCli.sh客户端zkCli.sh可以理解成客户端,也可以
- 概念二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:1、若它的左子树不为空,则左子树上所有节点的值都小于根结点的值。
- 用法1 为原始类型扩展方法先说一下,this 后面跟的类型,就是要拓展方法的类型。注意要写在静态类中的静态方法,不然有些情况下访问/// &
- 本文实例讲述了Android播放assets文件里视频文件相关问题。分享给大家供大家参考,具体如下:今天做了一个功能,就是播放项目工程里面的
- 延迟加载1 使用延迟加载意义在进行数据查询时,为了提高数据库查询性能,尽量使用单表查询,因为单表查询比多表关联查询速度要快。如果查询单表就可
- 前言: 哲学老师说,看待事物无非是了解它是什么,为什么,怎么做所以,首先,我们先了解一下什么是“内存泄漏”摘自百度的一段话:用动态存储分配函
- 本文实例讲述了ActiveMQ在C#中的应用。分享给大家供大家参考,具体如下:ActiveMQ是个好东东,不必多说。ActiveMQ提供多种
- 前言:本文主要介绍内容有:一个串行调用的例子(App首页信息查询)CompletionService实现并行调用抽取通用的并行调用方法代码思
- 使用YZMHelper帮助类即可using System;using System.Web;using System.Drawing;usi
- CardView介绍CardView是Android 5.0系统引入的控件,相当于FragmentLayout布局控件然后添加圆角及阴影的效
- 前言我们知道在Java中除了基础的数据类型以外,其它的都为引用类型。而Java根据其生命周期的长短将引用类型又分为强引用、软引用、弱引用、幻
- 本文实例为大家分享了Android实现京东上滑效果的具体代码,供大家参考,具体内容如下前言:现在很多app首页的结构都有头部广告,上滑固定t
- //直接插入排序void DirectInsertionSort(int* arr, in
- Spring Boot 为 Spring MVC 提供了自动配置,适用于大多数应用程序。官方文档描述:自动配置在 Spring 的默认值之上
- Java是一种强类型, 许多流行的编程语言都已经支持局部变量类型推断,如js,Python,C++等JDK10 可以使用var作为局部变量类
- 前言在这个系列博客的第二篇的最后部分提到了预布局,在预布局阶段,计算剩余空间时会把将要移除的 ViewHolder 忽略,从而计算出递补的
- 今天遇到了一个比较有意思的问题,从服务器上封装好的java.sql.timestamp对象返回到本地客户端程序后与数据库中的时间相差了整整1
- 一、简介WorkManager 用于处理 Android 后台任务。我们只需要设置好任务内容、何时执行,剩下的工作就可以完全交给系统处理。它
- 以前看到过个:Java开发手册(阿里巴巴-公开版),这是个pdf文档,里面描述了一些Java开发的规约,里面确实有很多好用的规约,要是在学校
- 相关方法:wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。notify():一旦执行此方法,就会唤醒被wait的一个