Buffer简单介绍

Buffer意为缓冲区。其本质上就是是一块可写入数据,然后能够从中读取数据的内存区域。通过该种方式有助于降低系统开销和提高外设效率。对于缓冲区我们早有所了解,比方在C中标准I/O中的read,write直接调用系统的输入输出。而scanf和printf则借助缓冲区在适当的时候调用read。write操作。在NIO中,为了方便对缓冲区的操作。jAVA设计者将缓冲区封装为Buffer(实际上就是封装了基本数据元素的数组),并提供对应的方法对其操作。

在開始之前,首先须要明确下面几个概念:

  • 读模式和写模式
  • Buffer的capacity
  • Buffer的position
  • Buffer的limit

读模式和写模式

对于一块内存区而言,将数据写入该区域的过程称之为写模式。反之,称之为读模式。

capacity

该内存的大小即数组的的容量称为Buffer的capacity。一旦Buffer满了,你须要将其清空才干继续写入数据。

position

Buffer当前游标的位置称为position。在写模式下position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后,position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1。当将Buffer从写模式切换到读模式,position会先被重置为0,然后当从Buffer的position处读取数据时。position向前移动到下一个可读的位置。

limit

在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。写模式下,limit等于Buffer的capacity。当切换Buffer到读模式时。limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时。limit会被设置成写模式下的position值。

换句话说,你能读到之前写入的全部数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

我们用一张图来大体的概括:


Buffer使用

Buffer的使用过程大体遵循下面步骤:

分配缓存大小——>写数据到Buffer——>调用其filp()——>从Buffer读取数据——>调用clear()或者compact()。



当向buffer写入数据时。buffer会记录下写了多少数据。

一旦要读取数据,须要通过flip()方法将Buffer从写模式切换到读模式。在读模式下。能够读取之前写入到buffer的全部数据。一旦读完了全部的数据。就须要清空缓冲区,让它能够再次被写入。

1. 创建Buffer

通过allocate()或者通过wrap()方法

  ByteBuffer byteBuffer=ByteBuffer.allocate(48)

  Byte[] bytes=new Byte[1024];
//通过该种方式将生成一个limit=capacity=bytes.length的新缓存区,假设bytes里含有数据,则会用该数据填充缓冲区。要注意的是通过该种方式创建的ByteBuffer其position初始值是0.
ByteBuffer byteBuffer=ByteBuffer.wrap(bytes);

2. 向Buffer中写数据

通过Channel的read方法。将数据写到Buffer
通过Buffer自身的put()方法 int bytesRead=fileChannel.read(byteBuffer);
byteBuffer.put(2);

3. 通过filp()进行模式转换

flip方法将Buffer从写模式切换到读模式。调用flip()方法会首先将limit的值设为当前position的值。然后将position设为0。相当运行了下面语句:
limit=position;
position=0;

换句话说,position如今用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 如今能读取多少个byte、char等。

4. 读取Buffer的数据

从Buffer读取数据到Channel
使用Buffer的get()方法读取Buffer的数据

5. 重读buffer中的数据

Buffer.rewind()将position设回0,所以你能够重读Buffer中的全部数据。limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)。

6. 清空Buffer

一旦读完Buffer中的数据,须要让Buffer准备好再次被写入。能够通过clear()或compact()方法来完毕。

假设调用的是clear()方法,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer相当于 被清空了(实际上Buffer中的内容并未真正被清空,此时假设调用rewind()或者设置position=0仍然可读取旧的数据)。

该方法实际上仅仅是重设了position和limit的值。进而告诉我们能够从哪里開始往Buffer里写数据。

假设Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有不论什么标记会告诉你哪些数据被读过。哪些还没有。

假设Buffer中仍有未读的数据。且兴许还须要这些数据,可是此时想要先先写些数据。那么使用compact()方法。

compact()方法将全部未读的数据复制到Buffer起始处。

然后将position设到最后一个未读元素正后面。limit属性依旧像clear()方法一样,设置成capacity。如今Buffer准备好写数据了,可是不会覆盖未读的数据。

7. 通过mark()标记position位置。在进行其它操作后可通过reset() 方法恢复到标记的position

buffer.mark()
...
buffer.reset()

Buffer完整演示样例

public class testBuffer {
public static void main(String[] args) {
/**
* 分配空间 隐含地在内存中分配了一个byte型数组来存储10个byte
*/
ByteBuffer buffer = ByteBuffer.allocate(10);
/**
* 填充元素 buffer.hasRemaining()用于推断缓冲区是否达到上界limit。 该填充过程等效于:int remainCount = buffer.remaining();for (int j = 0; j < remainCount;
* j++){buffer.put((byte) j++);}
*/
int i = 0;
while (buffer.hasRemaining()) {
buffer.put((byte) i++);
}
/**
* 翻转缓冲区 将缓冲区进行翻转操作,即在缓冲区写入完毕时,将缓冲区翻转成一个准备读出元素的状态。 flip操作等效于buffer.limit(buffer.position()).position(0);同一时候将mark设为-1。 源代码例如以下:public final Buffer
* flip(){ limit = position;position = 0;mark = -1;return this;}
*/
buffer.flip();
/**
* 读取缓冲区
*/
int remainCount = buffer.remaining();
for (int j = 0; j < remainCount; j++) {
System.out.print(buffer.get() + " ");
}
System.out.println(); /**
* 字节顺序
*/
System.out.println("ByteOrder的字节顺序为:" + ByteOrder.nativeOrder());
System.out.println("ByteBuffer的字节顺序为:" + buffer.order());
CharBuffer charBuffer = CharBuffer.allocate(10);
System.out.println("CharBuffer的字节顺序为:" + charBuffer.order());
// 改动ButyBuffer的字节顺序
buffer.order(ByteOrder.LITTLE_ENDIAN);
System.out.println("ByteBuffer的字节顺序为:" + buffer.order()); /**
* 仅仅有ByteBuffer能够创建直接缓冲区,用wrap函数创建的缓冲区都是非直接的缓冲区
*/
ByteBuffer redirectByteBuffer = ByteBuffer.allocateDirect(10);
System.out.println("推断缓冲区是否为直接缓冲区:" + redirectByteBuffer.isDirect()); /**
* 先创建一个大端字节顺序的ByteBuffer。然后再创建一个字符视图缓冲区
*/
ByteBuffer bigByteBuffer = ByteBuffer.allocate(7).order(ByteOrder.BIG_ENDIAN);
CharBuffer viewCharBuffer = bigByteBuffer.asCharBuffer(); viewCharBuffer.put("你好啊");
/**
* 在字符视图的基础上创建仅仅读字符视图,仅仅能读而不能写,否则抛出ReadOnlyBufferException
*/
CharBuffer onlyReadCharBuffer = viewCharBuffer.asReadOnlyBuffer(); viewCharBuffer.flip();
System.out.println("asCharBuffer()--->position=" + viewCharBuffer.position() + ",limit=" + viewCharBuffer.limit());
while (viewCharBuffer.hasRemaining()) {
System.out.println((char) viewCharBuffer.get());
} /**
* 创建一个与原始缓冲区类似的新缓冲区,两个缓冲区共享数据元素,拥有相同的容量,但每一个缓冲区拥有各自的位置、上界、标记属性。 对一个缓冲区的数据元素所做的改变会反映在还有一个缓冲区上。新的缓冲区会继承原始缓冲区的这些属性。 */
CharBuffer copyCharBuffer = viewCharBuffer.duplicate();
System.out.println("duplicate()--->position=" + copyCharBuffer.position() + ",limit=" + copyCharBuffer.limit());
copyCharBuffer.position(2);
while (copyCharBuffer.hasRemaining()) {
System.out.println((char) copyCharBuffer.get());
} /**
* 创建原始缓冲区子集的新缓冲区,新缓冲区的内容将从该缓冲区的当前位置開始。对这个缓冲区的内容做出的改变将在反映在新的缓冲区上,可见,反之亦然;这两个缓冲区的位置、限制和标记值将是独立的。
*/
viewCharBuffer.position(1);
CharBuffer cutCharBuffer = viewCharBuffer.slice();
System.out.println("slice()--->position=" + cutCharBuffer.position() + ",limit=" + cutCharBuffer.limit()+",capacity="+cutCharBuffer.capacity());
while (cutCharBuffer.hasRemaining()) {
System.out.println((char) cutCharBuffer.get());
} }
}

通俗编程——白话NIO之Buffer的更多相关文章

  1. Java网络编程和NIO详解8:浅析mmap和Direct Buffer

    Java网络编程与NIO详解8:浅析mmap和Direct Buffer 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NI ...

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

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

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

    微信公众号[黄小斜]作者是蚂蚁金服 JAVA 工程师,目前在蚂蚁财富负责后端开发工作,专注于 JAVA 后端技术栈,同时也懂点投资理财,坚持学习和写作,用大厂程序员的视角解读技术与互联网,我的世界里不 ...

  4. Java网络编程和NIO详解开篇:Java网络编程基础

    Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...

  5. Java网络编程和NIO详解9:基于NIO的网络编程框架Netty

    Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...

  6. Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

    Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...

  7. Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型

    Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...

  8. Java网络编程和NIO详解3:IO模型与Java网络编程模型

    Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...

  9. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...

随机推荐

  1. python对XML 操作

    一.XML的读取. 在 NewEdit 中有代码片段的功能,代码片段分为片段的分类和片段的内容.在缺省情况下都是用XML格式保存的.下面我讲述一下,如何使用minidom来读取和保存XML文件. 下面 ...

  2. 2-2 第二天 利用 QQ 浏览器代理调试端口

    在没有域名服务器的情况下微信代理的方案 echo "api_key: N3DYn5356kYDvcd67fRxoecKxQV7fTE0" > ~/.ultrahook gem ...

  3. 什么是 less? 如何使用 less?

    什么是 Less? Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量.混合(mixin).嵌套.函数等功能,让 CSS 更易编写.维护等. 本质上,Less 包含一套自定义 ...

  4. PCB LDI文件 自动化输出(改造)实现思路

    由于工厂采用Liunxs系统输出LDI文件,由于我们数据库是用的Windows Server,编程语言是.net 无法与Liunxs系统进行有效对接, 所以造成才会造成LDI 资料输效率极低,人员工作 ...

  5. javascript 原型(prototype 、__proto__、函数、对象)

    一.类型 1.JavaScript中分为值类型(string/boolean/null/number/undefind).引用类型(数组.对象.函数): 2.数组.函数.对象都是对象: 对象是由函数创 ...

  6. ThreadLocal,静态变量,实例变量,局部变量的线程安全

    之前都是业务层次开发,现在公司进行的网络编程,一下子要了解太多java底层的东西并进行应用,我现在边学习边应用.由于知识能力有限,在上次发博客时出现了一个小小的纰漏,而这个纰漏被细心的博友发现了. 首 ...

  7. spring框架搭建(一)

    spring介绍 spring是一个轻量级控制反转(IOC)和面向切面(AOP)的容器框架,它主要是为了解决企业应用开发复杂性而诞生的. 简单来说spring是一个一站式轻量级开源框架. IOC:In ...

  8. 判断wifi是2.4G还是5G

    1.WifiInfo 源码: int mFrequency=wifiInfo.getFrequency(); /** * @hide * TODO: makes real freq boundarie ...

  9. 网上找的JS截取字符串(含中文)

    <script> /* 2007-11-28 XuJian */ //截取字符串 包含中文处理 //(串,长度,增加...) function subString(str, len, ha ...

  10. Python之global

    1 Global The global statement and its nonlocal cousin are the only things that are remotely like dec ...