详解 缓冲区(Buffer 抽象类)
在本篇博文中,本人主要讲解NIO 的两个核心点 —— 缓冲区(Buffer) 和 通道 (Channel)之一的 缓冲区(Buffer),
有关NIO流的其他知识点请观看本人博文《详解 NIO流》
缓冲区(Buffer 类):
简介:
缓冲区( Buffer ):
一个用于特定基本数据类型的容器。
由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类。
Java NIO 中的 Buffer 主要用于与 NIO 通道进行交互,
数据是从通道读入缓冲区,从缓冲区写入通道中的
Buffer 就像一个数组,可以保存多个相同类型的数据
那么,现在,本人来介绍下Buffer 抽象类的 常用子类:
ByteBuffer —— 存储byte类型的缓冲区
CharBuffer —— 存储char类型的缓冲区
ShortBuffer —— 存储short类型的缓冲区
IntBuffer —— 存储int类型的缓冲区
LongBuffer —— 存储long类型的缓冲区
FloatBuffer —— 存储float类型的缓冲区
DoubleBuffer —— 存储double类型的缓冲区
上述 Buffer 类 他们都采用相似的方法进行管理数据,
只是各自管理的数据类型不同而已。
Buffer是没有构造方法的,
Buffer的对象都是通过 allocate(int capacity)方法 来获取的
现在,本人来讲解下如何获取 Buffer 抽象类 的 子类的对象:
手段1:
直接缓冲区:子类的allocateDirect()静态方法
非直接缓冲区:子类的allocate()静态方法
手段2:
直接缓冲区:通过 FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建。(该方法返回MappedByteBuffer )
那么,本人现在来展示下处理缓冲区的核心API:
核心API:
put() 存入数据到缓冲区中
get() 获取缓冲区中的数据
flip() 切换读取数据模式
rewind() 可重复读
clear() 清空缓冲区. 但是缓冲区中的数据依然存在,但是处于“被遗忘”状态
mark() 标记是一个索引,方便后面使用reset()方法跳回这标记处
reset() 使position恢复到之前用mark()方法标记的
现在,本人来讲解下Buffer的基本属性:
Buffer的基本属性:
Buffer 中的重要属性:
容量 (capacity) :
表示 Buffer 最大数据容量。
缓冲区容量不能为负,并且创建后不能更改。
限制 (limit) :
第一个不应该读取或写入的数据的索引,即位于 limit 后的数据不可读写。
缓冲区的限制不能为负,并且不能大于其容量。
位置 (position) :
下一个要读取或写入的数据的索引。
缓冲区的位置不能为负,并且不能大于其限制
标记 (mark) 与重置 (reset) :
标记是一个索引,
通过 Buffer 中的 mark() 方法 指定 Buffer 中一个特定的 position ,之后可以通过调用 reset() 方法恢复到这个 position.
标记、位置、限制、容量遵守以下不变式:
下图展示了处理缓冲区的API 会对缓冲区的属性的影响:
现在,本人来展示下Buffer类的API:
Buffer的API:
方法 描述
Buffer clear() 清空缓冲区并返回对缓冲区的引用
Buffer flip() 将缓冲区的界限设置为当前位置,并将当前位置充值为0
int capacity() 返回Buffer的capacity大小
boolean hasRemaining() 判断缓冲区中是否还有元素
int limit() 返回Buffer的界限(limit)的位置
Buffer limit(intn) 将设置缓冲区界限为n,并返回一个具有新limit的缓冲区对象
Buffer mark() 对缓冲区设置标记
int position() 返回缓冲区的当前位置position
Buffer position(int n) 将设置缓冲区的当前位置为n,并返回修改后的Buffer对象
int remaining() 返回position和limit之间的元素个数
Buffer reset() 将位置position转到以前设置的mark所在的位置
Buffer rewind() 将位置设为为0,取消设置的mark
那么,现在,本人来通过一个例子来展示下这些API 的使用:
package edu.youzg.about_nio.core;
import java.nio.ByteBuffer;
public class Test {
public static void main(String[] args) {
String str="youzhuange";
//申请10字节缓冲区空间
System.out.println("--------------allocate(10)-------");
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
int capacity = byteBuffer.capacity();
int position = byteBuffer.position();
int limit = byteBuffer.limit();
System.out.println("capacity:"+capacity);
System.out.println("position:"+position);
System.out.println("limit:"+limit);
//往容器中放数据 put();
System.out.println("----------put()-----------");
byteBuffer.put(str.getBytes());
capacity = byteBuffer.capacity();
position = byteBuffer.position();
limit = byteBuffer.limit();
System.out.println("capacity:" + capacity);
System.out.println("position:" + position);
System.out.println("limit:" + limit);
//读取缓冲区中的数据,切换成读取模式
System.out.println("---------flip()--------");
byteBuffer.flip();
capacity = byteBuffer.capacity();
position = byteBuffer.position();
limit = byteBuffer.limit();
System.out.println("capacity:" + capacity);
System.out.println("position:" + position);
System.out.println("limit:" + limit);
//读取数据 get()
System.out.println("---------get()---------");
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.get(bytes);
System.out.println(new String(bytes, 0, byteBuffer.limit()));
capacity = byteBuffer.capacity();
position = byteBuffer.position();
limit = byteBuffer.limit();
System.out.println("capacity:" + capacity);
System.out.println("position:" + position);
System.out.println("limit:" + limit);
//可重复读取
System.out.println("---------rewind()---------");
byteBuffer.rewind();
capacity = byteBuffer.capacity();
position = byteBuffer.position();
limit = byteBuffer.limit();
System.out.println("capacity:" + capacity);
System.out.println("position:" + position);
System.out.println("limit:" + limit);
//标记 mark
System.out.println("---------mark()--------");
byteBuffer.mark();
byteBuffer.get(bytes,2,2);
System.out.println(byteBuffer.position());
//回到上一次标记position的位置 使用reset();就可以回到上一次标记的位置
System.out.println("---------reset()--------");
byteBuffer.reset();
System.out.println(byteBuffer.position());
//查询还有没有可读数据
System.out.println("---------remaining()--------");
if(byteBuffer.hasRemaining()){
System.out.println(byteBuffer.remaining()); //remaining()还有多少可读取数据
}
//清空缓冲区
System.out.println("--------clear()----------------");
//clear()并不是把缓冲区里面的字节数据清掉,而是把这些指针,设置到初始状态
byteBuffer.clear();
capacity = byteBuffer.capacity();
position = byteBuffer.position();
limit = byteBuffer.limit();
System.out.println("capacity:" + capacity);
System.out.println("position:" + position);
System.out.println("limit:" + limit);
byte b = byteBuffer.get();
System.out.println((char)b);
}
}
本人再来展示下运行结果:
那么,现在,本人来讲解缓冲区的分类 —— 直接缓冲区 与 非直接缓冲区:
字节缓冲区要么是直接的,要么是非直接的。
直接缓冲区是将 缓冲区建立在 物理内存中,非直接缓冲区是将缓冲区建立在JVM中
如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操作。
也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),
虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。
直接字节缓冲区可以通过调用此类的 allocateDirect() 工厂方法 来创建。
此方法返回的 缓冲区进行分配和取消分配所需成本通常高于 非直接缓冲区 。
直接缓冲区的内容 可以驻留在常规的垃圾回收堆之外,
因此,它们对应用程序的内存需求量造成的影响可能并不明显。
所以,建议将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操作影响的大型、持久的缓冲区。
一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。
直接字节缓冲区还可以通过 FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建。
该方法返回MappedByteBuffer 。
Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。
如果以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,
则试图访问该区域不会更改该缓冲区的内容,并且将会在访问期间或稍后的某个时间导致抛出不确定的异常。
字节缓冲区是直接缓冲区还是非直接缓冲区 可通过调用其 isDirect() 方法来确定。
提供此方法是为了能够在性能关键型代码中执行显式缓冲区管理。
现在,本人来通过两张图来展示下这两种缓冲区的底层传输步骤:
至于这两种缓冲区的使用,请观看本人博文 —— 《详解 通道 (Channel 接口)》
现在,本人对上图中的内存映射文件为什么高效率做下解释:
内存映射文件效率为什么高:
文件I/O的读操作,
会先向文件设备发起读请求,驱动把请求要读的数据读取到文件的缓冲区中(这个缓冲区位于内核),
然后再把这个缓冲区中的数据复制到程序虚拟地址空间中的一块区域中。
文件I/O的写操作,
会向文件设备发起写请求,驱动把要写入的数据复制到程序的缓冲区中(位于用户空间),
然后再把这个缓冲区的数据复制到文件的缓冲区中。
内存映射文件,是把位于硬盘中的文件看做是程序地址空间中一块区域对应的物理存储器,
文件的数据就是这块区域内存中对应的数据,读写文件中的数据,直接对这块区域的地址操作 就可以,
减少了内存复制的环节。
所以说,内存映射文件比起文件I/O操作,效率要高,而且文件越大,体现出来的差距越大。
(本人 NIO流 博文链接:https:////www.cnblogs.com/codderYouzg/p/12418765.html)
详解 缓冲区(Buffer 抽象类)的更多相关文章
- 第7.20节 案例详解:Python抽象类之真实子类
第7.20节 案例详解:Python抽象类之真实子类 上节介绍了Python抽象基类相关概念,并介绍了抽象基类实现真实子类的步骤和语法,本节结合一个案例进一步详细介绍. 一. 案例说明 本节定义 ...
- 详解java基础--抽象类、接口与多态
抽象类.接口.多态都是面向对象中很基础的东西,我相信看到能本篇博客的人本不会再纠结它的基本定义了,本篇文章将尽量的更加深层次的挖掘其内涵,希望能对大家有帮助. 一.抽象类 1.形式 abstract ...
- 详解 NIO流
在观看本篇博文前,建议先观看本人博文 -- <详解 IO流> NIO流: 首先,本人来介绍下什么是NIO流: 概述: Java NIO ( New IO )是从 Java 1.4 版本开始 ...
- Java NIO ———— Buffer 缓冲区详解 入门
引言缓冲区是一个用于特定基本类型的容器.由java.nio 包定义,所有缓冲区都是 Buffer 抽象类的子类. Java NIO 中的 Buffer ,主要用于与NIO 通道进行交互.数据从通道存入 ...
- java NIO Buffer 详解(1)
1.java.io 最为核心的概念是流(stream),面向流的编程,要么输入流要么输出流,二者不可兼具: 2.java.nio 中拥有3个核心概念: Selector Channel, Buffe ...
- Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector
Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首 ...
- 【Qt开发】V4L2 API详解 Buffer的准备和数据读取
前面主要介绍的是:V4L2 的一些设置接口,如亮度,饱和度,曝光时间,帧数,增益,白平衡等.今天看看V4L2 得到数据的几个关键ioctl,Buffer的申请和数据的抓取. 1. 初始化 Memory ...
- Protocol Buffer技术详解(数据编码)
Protocol Buffer技术详解(数据编码) 之前已经发了三篇有关Protocol Buffer的技术博客,其中第一篇介绍了Protocol Buffer的语言规范,而后两篇则分别基于C++和J ...
- Protocol Buffer技术详解(Java实例)
Protocol Buffer技术详解(Java实例) 该篇Blog和上一篇(C++实例)基本相同,只是面向于我们团队中的Java工程师,毕竟我们项目的前端部分是基于Android开发的,而且我们研发 ...
随机推荐
- ArcGIS中影像图去黑边
通常情况下有些影像图的背景会显示黑色,所以需要将影像图的格式转换一下,将黑色背景转换为透明色.具体去除河边的步骤如下: 1.在catalog中,选中要转换的影像图: 2.右键——导出——将栅格导出为不 ...
- python中的可变和不可变对象 有序和无序对象
可变对象和不可变对象的定义:对象存放在地址的值是否可以被改变 不可变对象包括:整形int.浮点型float .字符串str .元祖tuple.布尔型boole 可变对象包括 :列表list.集合set ...
- python—json
一.json数据类型:是字符串 # json通用数据类型,所有语言都可以用 # {k-v}形式存在,里面只能用双引号"" # 定义json字符串,要用'''{}'''格式 #htt ...
- 数据库连接JOIN
1,连接类型及差异 INNER JOIN:结果集只有配对成功的数据,即不包含左表或右表为空的情况: OUTER JOIN: LEFT JOIN:结果包含左表的所有记录,右表不能成功匹配的显示NULL ...
- Gin框架系列01:极速上手
Gin是什么? Gin是Go语言编写的web框架,具备中间件.崩溃处理.JSON验证.内置渲染等多种功能. 准备工作 本系列演示所有代码都在Github中,感兴趣的同学可以自行查阅,欢迎大家一起完善. ...
- 白话web安全
伤心往事 梦回大二,那时候沉迷于毒奶粉,甚至国庆都在宿舍与毒奶粉共同度过,但是却发生了一件让我迄今难忘的事情~ 我新练的黑暗武士被盗了!!!干干净净!!! 虽然过了好久了,但是记忆犹新啊,仿佛发生在昨 ...
- Javascript/Jquery遇到字符串自动NaN的问题
结果发现是一个id绑定了两次点击事件.修改之后,问题解决.
- MiniUi遇到的一个Bug或者说坑,以div里面的内容自适应高度
页面源码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <tit ...
- js检查数据类型
在实际工作中我们经常遇到要检测传入的参数类型是什么.也许第一时间想的的是typeof ,但这个也只是能检测个别的一些类型.如果要检测null,Array这些类型呢? 所以我们可以封装一个方法可以更加方 ...
- 第一次将本地项目push到github
问题:github有一个空项目,将本地项目上传到github空项目时,报错如下 $ git push --set-upstream git@github.com:dslu7733/promise.gi ...