NIO(一):Buffer缓冲区
一.NIO与IO:
IO: 一般泛指进行input/output操作(读写操作),Java IO其核心是字符流(inputstream/outputstream)和字节流(reader/writer)做为基本进行操作,只能做单向操作,而IO的读写方式采用流的方式进行读写操作,如图所示

对于NIO既可以说是(NEW NIO) 也是(NON Blocking IO),为什么说他的性能和效率高于IO流,其的传输方式采用块传输方式,也就是使用缓冲区(buffer),使用channel(通道)进行双向传输。

其关键三个API为:
channel(通道): 实现数据的双向输出
Buffer(缓冲区):用于存储临时的读写数据
Selector(选择器) 若干客户端在Selector中注册自己,若干channel注册到Selector中,通过选择操作选出就绪的键,通道线程来实现少量线程的为多个客户端服务
二.Buffer缓冲区
什么是缓冲区?Buffer 是一个对象, 它包含一些要写入或者刚读出的数据。 在 NIO 中加入 Buffer 对象,体现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中,您将数据直接写入或者将数据直接读到 Stream 对象中。
在内存中开辟一段连续的区域,进行临时存储,实际上缓冲区为一个数组,在Buffer中可以进行存储的数据类型为:
CharBuffer
FloatBuffer
IntBuffer
DoubleBuffer
ShortBuffer
LongBuffer
ByteBuffer
这些基本的实现都继承自Buffer类。
Buffer中定义了4个属性为:
private int mark = -1; //此属性将在随后说到
private int position = 0;
private int limit;
private int capacity;
其中:
不变性(以1,2,3,4为从低到高排序) |
||
position |
即将被读或写的位置 |
2 |
limit |
限制最大取出值/放入值,注意:position < limit |
3 |
capacity |
缓冲区中可以存储的最大容量 |
4 |
mark |
标记位置,用于标记某一次的读取/写入的位置 |
1 |
三.以ByteBuffer为例
在进行读写操作前需要开辟一个区域,对ByteBuffer进行初始化操作。
继承体系:

ByteBuffer bf = ByteBuffer.allocate(1024);
在使用allocate初始化中,进入方法中,当容量为负时,返回一个异常,反之初始化一个HeapByteBuffer
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
并进行对属性进行赋值并创建一个相应容量的Byte数组
HeapByteBuffer(int cap, int lim) { // package-private
super(-1, 0, lim, cap, new byte[cap], 0);
/*
hb = new byte[cap];
offset = 0;
*/
}
ByteBuffer(int mark, int pos, int lim, int cap, // package-private
byte[] hb, int offset)
{
super(mark, pos, lim, cap);
this.hb = hb;
this.offset = offset;
}
由此完成便开辟一个区域用来存储数据
使用position 方法,limit方法,capacity方法查询相关信息,根据上面例子创建一个1024容量的缓冲区
//存储位置
System.out.println("position:---"+bf.position());
//存储限制大小
System.out.println("limit:---"+bf.limit());
//存储容量
System.out.println("capacity:---"+bf.capacity());

此时position所指向0的位置。limiit所指向1024的位置。

随后在进行写操作时使用put进行写入操作,
//为缓存区中存入数据
System.out.println("-------------put写入-------------");
//定义一个数据
String str= "123456";
bf.put(str.getBytes()); //将结果存储到新的字节数组中。
System.out.println("position:---"+bf.position());
System.out.println("limit:---"+bf.limit());
System.out.println("capacity:---"+bf.capacity());
此时:

那么position是如何得知的那?
通过在HeapByteBuffer中position初始化为0+数据转化为byte数组后的长度加起来得到position的值。并记录
写入时,position < limit 此时limit没有变化,
public ByteBuffer put(byte[] src, int offset, int length) {
checkBounds(offset, length, src.length);
if (length > remaining())
throw new BufferOverflowException();
System.arraycopy(src, offset, hb, ix(position()), length);
position(position() + length);
return this;
这就完成了数据的写入,当想在缓冲区中读取数据时,在需要先切换至读取状态,使用flip方法,在Buffer中的flip方法中 ,定义了将position赋给limit 限制读取的最大长度。并使position置为0
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
进行切换状态
//写入 后切换为读取状态
System.out.println("-------------flip切换-------------");
/*
* 将limit = position
* 令 position = 0
* */
bf.flip(); //切换读取状态
System.out.println("position:---"+bf.position());
System.out.println("limit:---"+bf.limit());
System.out.println("capacity:---"+bf.capacity());

此时:

切换完成后,便进行读的操作。
//切换成功后进行读取
System.out.println("-------------get读取-------------");
/*
* 从零开始读 ,读6个长度停止
* */
bf.get(str.getBytes(), 0, 6);
System.out.println("position:---"+bf.position());
System.out.println("limit:---"+bf.limit());
System.out.println("capacity:---"+bf.capacity());


你也可以并不止于读写,还可以清空缓冲区。使用clear方法
/**
* Clears this buffer. The position is set to zero, the limit is set to
* the capacity, and the mark is discarded.
*
* <p> Invoke this method before using a sequence of channel-read or
* <i>put</i> operations to fill this buffer. For example:
*
* <blockquote><pre>
* buf.clear(); // Prepare buffer for reading
* in.read(buf); // Read data</pre></blockquote>
*
* <p> This method does not actually erase the data in the buffer, but it
* is named as if it did because it will most often be used in situations
* in which that might as well be the case. </p>
*
* @return This buffer
*/
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
根据官方注释解释,这里清除并非真正的清除数据,而是抹去了存在的痕迹。使它被遗忘掉。数据也是可读的。
//清空缓存区
System.out.println("-------------clear清空-------------"); bf.clear();
System.out.println("position:---"+bf.position());
System.out.println("limit:---"+bf.limit());
System.out.println("capacity:---"+bf.capacity());
//查看实际是否存在数据,并未被清除,只是被遗忘了。
System.out.println((char)bf.get(0));
System.out.println((char)bf.get(1));

此时:

在Buffer中还提供了一些方法如下:
rewind() |
对缓冲区存入的数据重复读 |
remaining() |
统计属性间的元素数limit - position |
hasRemaining() |
统计当前位置中是否还有数据 |
部分引用内容载自:https://www.cnblogs.com/imstudy/p/11108085.html
NIO(一):Buffer缓冲区的更多相关文章
- Nio再学习之NIO的buffer缓冲区
1. 缓冲区(Buffer): 介绍 我们知道在BIO(Block IO)中其是使用的流的形式进行读取,可以将数据直接写入或者将数据直接读取到Stream对象中,但是在NIO中所有的数据都是使用的换冲 ...
- Java NIO 之 Buffer(缓冲区)
一 Buffer(缓冲区)介绍 Java NIO Buffers用于和NIO Channel交互. 我们从Channel中读取数据到buffers里,从Buffer把数据写入到Channels. Bu ...
- JAVA NIO简介-- Buffer、Channel、Charset 、直接缓冲区、分散和聚集、文件锁
IO 是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. Java标准io回顾 在Java1.4之前的I/O系统中,提供 ...
- Java NIO Buffer缓冲区
原文链接:http://tutorials.jenkov.com/java-nio/buffers.html Java NIO Buffers用于和NIO Channel交互.正如你已经知道的,我们从 ...
- Java NIO中的缓冲区Buffer(一)缓冲区基础
什么是缓冲区(Buffer) 定义 简单地说就是一块存储区域,哈哈哈,可能太简单了,或者可以换种说法,从代码的角度来讲(可以查看JDK中Buffer.ByteBuffer.DoubleBuffer等的 ...
- Java NIO之Buffer(缓冲区)
Java NIO中的缓存区(Buffer)用于和通道(Channel)进行交互.数据是从通道读入缓冲区,从缓冲区写入到通道中的. 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这 ...
- NIO入门之缓冲区Buffer
缓存区 Buffer 是数据容器 ByteBuffer 可以存储除了 boolean 以外的其他 7 种Java基本数据类型,如 getInt.putInt Buffer 是抽象类,它有除了 Bool ...
- Java NIO(2):缓冲区基础
缓冲区(Buffer)对象是面向块的I/O的基础,也是NIO的核心对象之一.在NIO中每一次I/O操作都离不开Buffer,每一次的读和写都是针对Buffer操作的.Buffer在实现上本质是一个数组 ...
- NIO基础学习——缓冲区
NIO是对I/O处理的进一步抽象,包含了I/O的基础概念.我是基于网上博友的博客和Ron Hitchens写的<JAVA NIO>来学习的. NIO的三大核心内容:缓冲区,通道,选择器. ...
随机推荐
- java IO流 (一) File类的使用
1.File类的理解* 1. File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)* 2. File类声明在java.io包下* 3. File类中涉及到关于文件或文件目录的创建.删除.重 ...
- redis(二十一):Redis 架构模式实现(哨兵)
先了解一下哨兵都 做了什么工作:Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务: 监控(Monitoring): Sentinel ...
- softmax、cross entropy和softmax loss学习笔记
之前做手写数字识别时,接触到softmax网络,知道其是全连接层,但没有搞清楚它的实现方式,今天学习Alexnet网络,又接触到了softmax,果断仔细研究研究,有了softmax,损失函数自然不可 ...
- 深度学习论文翻译解析(十):Visualizing and Understanding Convolutional Networks
论文标题:Visualizing and Understanding Convolutional Networks 标题翻译:可视化和理解卷积网络 论文作者:Matthew D. Zeiler Ro ...
- three.js 曲线
上几篇说了three.js的曲线,这篇来郭先生来说说three.js曲线,在线案例点击郭先生的博客查看. 1. 了解three.js曲线 之前已经说了一些three.js的几何体,这篇说一说three ...
- bzoj3196Tyvj1730二逼平衡树
bzoj3196Tyvj1730二逼平衡树 题意: 维护一个数列,操作:查询k在区间内的排名.查询区间内排名为k的值3.修改某一位上的数值.查询k在区间内的前驱(前驱定义为小于x,且最大的数).查询k ...
- ASP.NET Core3.1使用Identity Server4建立Authorization Server-2
前言 建立Web Api项目 在同一个解决方案下建立一个Web Api项目IdentityServer4.WebApi,然后修改Web Api的launchSettings.json.参考第一节,当然 ...
- 改造 layui 表格组件实现多重排序
layui 的表格组件目前只支持单列排序,在实际应用中并不能很好的支撑我们的业务需求.今天一时手痒,决定改造一番以支持多重排序. 实现思路也比较简单,只需要用一个数组来存放所有排序的列,再把这个数组传 ...
- 【Nginx】如何为已安装的Nginx动态添加模块?看完我懂了!!
写在前面 很多时候,我们根据当时的项目情况和业务需求安装完Nginx后,后续随着业务的发展,往往会给安装好的Nginx添加其他的功能模块.在为Nginx添加功能模块时,要求Nginx不停机.这就涉及到 ...
- SpringCloud或SpringBoot+Mybatis-Plus利用AOP+mybatis插件实现数据操作记录及更新对比
引文 本文主要介绍如何使用Spring AOP + mybatis插件实现拦截数据库操作并根据不同需求进行数据对比分析,主要适用于系统中需要对数据操作进行记录.在更新数据时准确记录更新字段 核心:AO ...