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的三大核心内容:缓冲区,通道,选择器. ...
随机推荐
- Centos7:python 安装。yum安装软件提示 cannot find a valid baseurl for repobase7x86_64
方法一. 1.打开 vi /etc/sysconfig/network-scripts/ifcfg-enp4s0(每个机子都可能不一样,但格式会是“ifcfg-e...”).但内容包含: < ...
- Zabbix 4.0 API 实践,主机/主机群组 批量添加模板和删除模板
场景 我们日常在管理Zabbix 的时候,经常会需要批量添加模板和批量删除模板,Zabbix页面是提供的批量链接的功能,但是它链接的也只是当前页的主机,我们想扩展这个功能,在链接的时候,可以批量链接整 ...
- 手写简易SpringMVC
手写简易SpringMVC 手写系列框架代码基于普通Maven构建,因此在手写SpringMVC的过程中,需要手动的集成Tomcat容器 必备知识: Servlet相关理解和使用,Maven,Java ...
- oracle数据库查询分组之外的数据方法
select * from (select t.*,row_number() over(partition by 分组字段 order by rownum) rn from 表名 t where 条件 ...
- 解决Kubernetes Pod故障的5个简单技巧
在很多情况下,你可能会发现Kubernetes中的应用程序没有正确地部署,或者没有正常地工作.今天这篇文章就提供了如何去快速解决这类故障以及一些技巧. 在阅读了这篇文章之后,你还将深入了解Kubern ...
- 3.新手建站教程系列之认识WordPress和第一篇文章
上一期咱已经把本地环境和wp网站给搭建出来了,接下来就是来认识这个程序了.进入网站后台,地址为你的网址/wp-admin 后台名字叫做仪表盘,首页是一个信息合集区域,上面会显示有多少文章,多少页面以及 ...
- Python虚拟环境(virtualenv)
python虚拟环境 虚拟环境:一个独立的可以运行的python执行环境,可以创建多个,且相互之间互不影响 使用virtualenv库 pip install virtualenv 用法 # 创建虚拟 ...
- webpack的使用 一、webpack 和webpack的安装
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler).当 webpack 处理应用程序时, 它会递归地构建一个依赖关系图(dependen ...
- mybatis sqlsession与sqlsquery、transaction、connection
sqlsession和connection 一个sqlsession一般对应一个connection,并且mybatis默认每次获取session都会开启一个事务,且不自动提交事务.如果更新操作完成后 ...
- SQL语法入门
SQL语句概述 ·SQL定义:是一种特定目的编程语言,用于管理关系数据库 ·GaussDB T是一种关系数据库,SQL语句包括 1.DDL 数据定义语言,用于定义或修改数据库中的对象(表,视图,序列, ...