在本篇博文中,本人主要讲解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 抽象类)的更多相关文章

  1. 第7.20节 案例详解:Python抽象类之真实子类

    第7.20节 案例详解:Python抽象类之真实子类 上节介绍了Python抽象基类相关概念,并介绍了抽象基类实现真实子类的步骤和语法,本节结合一个案例进一步详细介绍. 一.    案例说明 本节定义 ...

  2. 详解java基础--抽象类、接口与多态

    抽象类.接口.多态都是面向对象中很基础的东西,我相信看到能本篇博客的人本不会再纠结它的基本定义了,本篇文章将尽量的更加深层次的挖掘其内涵,希望能对大家有帮助. 一.抽象类 1.形式 abstract ...

  3. 详解 NIO流

    在观看本篇博文前,建议先观看本人博文 -- <详解 IO流> NIO流: 首先,本人来介绍下什么是NIO流: 概述: Java NIO ( New IO )是从 Java 1.4 版本开始 ...

  4. Java NIO ———— Buffer 缓冲区详解 入门

    引言缓冲区是一个用于特定基本类型的容器.由java.nio 包定义,所有缓冲区都是 Buffer 抽象类的子类. Java NIO 中的 Buffer ,主要用于与NIO 通道进行交互.数据从通道存入 ...

  5. java NIO Buffer 详解(1)

    1.java.io  最为核心的概念是流(stream),面向流的编程,要么输入流要么输出流,二者不可兼具: 2.java.nio 中拥有3个核心概念: Selector Channel, Buffe ...

  6. Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector

    Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首 ...

  7. 【Qt开发】V4L2 API详解 Buffer的准备和数据读取

    前面主要介绍的是:V4L2 的一些设置接口,如亮度,饱和度,曝光时间,帧数,增益,白平衡等.今天看看V4L2 得到数据的几个关键ioctl,Buffer的申请和数据的抓取. 1. 初始化 Memory ...

  8. Protocol Buffer技术详解(数据编码)

    Protocol Buffer技术详解(数据编码) 之前已经发了三篇有关Protocol Buffer的技术博客,其中第一篇介绍了Protocol Buffer的语言规范,而后两篇则分别基于C++和J ...

  9. Protocol Buffer技术详解(Java实例)

    Protocol Buffer技术详解(Java实例) 该篇Blog和上一篇(C++实例)基本相同,只是面向于我们团队中的Java工程师,毕竟我们项目的前端部分是基于Android开发的,而且我们研发 ...

随机推荐

  1. 【SQL SERVER重新认识】数据内部存储结构简单探索

    数据库经常需要打交道,但是从来没想过数据库内部是如何存储数据. 今天探索一下数据库内部如何存储数据,从下面几个方面探索 数据库内部如何存储数据 索引数据如何存储 操作数据对存储影响 总结 数据库内部如 ...

  2. 使用 PyTorch 进行 风格迁移(Neural-Transfer)

    1.简介 本教程主要讲解如何实现由 Leon A. Gatys,Alexander S. Ecker和Matthias Bethge提出的Neural-Style 算法.Neural-Style 或者 ...

  3. SpringCloud微服务架构和SOA架构

    1,传统的三层架构 在传统的架构中,SSH,SSM,主要分为web 控制层,业务逻辑层,数据库访问层,单点项目,项目没有拆分,所有的开发任务全部写在一个项目中,耦合度比价高,如果程序中的一个功能出现了 ...

  4. 基于vue-cli-和element-ui的开发admin(1)

    //首先以下仅是记录个人本次vue后台管理系统的登录界面部分操作的流程以及踩坑的注意点 一.首先是搭建vue-cli工作环境 这里有两种方式:1.用npm:(在安装了vue,vue-cli以及webp ...

  5. Codeforces #614 div.2 (A-E)

    A  ConneR and the A.R.C. Markland-N #include <bits/stdc++.h> using namespace std; #define ll l ...

  6. Infrared-Visible Cross-Modal Person Re-Identification with an X Modality (AAAI 2020)

    Infrared-Visible Cross-Modal Person Re-Identification with an X Modality (AAAI 2020) 1. Motivation 可见 ...

  7. 【cs224w】Lecture 4 - 社区结构

    Community 转自本人:https://blog.csdn.net/New2World/article/details/105328390 之前讲到了网络中节点扮演不同角色,而角色这个概念和社区 ...

  8. JavaScript new 的时候到底发生了什么?

    function Person(name) { this.name = name; } let liLei = new Person('lilei'); console.log(liLiei.name ...

  9. 面试总结:关于MySQL事务的10个问题常见面试问答(FQA)

    学习关系型数据库MySQL是很好的切入点,大部分人工作中用惯了CRUD,对面试官刨根问底的灵魂拷问你还能对答如流吗?我们有必要了解一些更深层次的数据库基础原理. 文章每周持续更新,各位的「三连」是对我 ...

  10. (CSS):last-child与:last-of-type区别

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>la ...