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. android 从assets和res中读取文件(转)

    1. 相关文件夹介绍      在Android项目文件夹里面,主要的资源文件是放在res文件夹里面的.assets文件夹是存放不进行编译加工的原生文件,即该文件夹里面的文件不会像xml,java文件 ...

  2. C语言和C++的应用领域都在哪些?学C语言好,还是学习C++好?

    从事嵌入式开发十几年,基本上围绕着这两种编程语言展开,都可以直接操作底层的编程语言,用的越熟练越是感觉工具属性越强.虽然两种编程语言分属于不同的编程思想,用的时间长了觉得差异也不是很大,现在就个人的从 ...

  3. idea使用svn

    一.在idea中配置svn 二.导出maven项目 连接svn 点击checkout 点击ok就可以 到Commit Changes 这里有几个选项需要了解的: Auto-update after c ...

  4. [SDOI2004]打鼹鼠

    ...... 心血来潮,手打abs 结果...BZOJ上CE,洛谷上WA... 把宏定义换成函数就过了 显然一个点可以走到另一个点,当且仅当两点鼹鼠出现时间$\leq$两点间距离的曼哈顿距离 显然是D ...

  5. dotnet core 发布配置(测试数据库和正式数据库自动切换)

    一.起源 在进行项目开发时,常常要求开发环境,测试环境及正式环境的分离,并且不同环境运行的参数都是不一样的,比如监听地址,数据库连接信息等.当然我们把配置信息保存到一个文件中,每次发布的时候,可以先修 ...

  6. 在PL/SQL中使用游标、动态sql和绑定变量的小例子

    需求:查询并输出30号部门的雇员信息 方式一:使用 loop...fetch SET serveroutput ON; DECLARE CURSOR c_emp IS ; v_emp emp%rowt ...

  7. swift-自定义TabBar工具栏

    class EBTAppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(ap ...

  8. 三星A3、A5、A7、G7、J5、J7、S6系列等新机型的部分手机解锁 ROOT刷机

    三星A3.A5.A7.G7.J5.J7.S6系列等新机型的部分手机,三星官方加了限制,需要解锁后才能刷机如果没有解锁,刷第三方recovery或者刷非官方原版固件,都会刷不进,手机跳转到提示界面,显示 ...

  9. C#设置开机启动项、取消开机启动项

    如果想你写的程序随系统开机一起启动的话,那么你可以照下面这个方法来做. RunWhenStart(false, Application.ProductName, Application.Startup ...

  10. tp实现多语言支持测试

    用tp框架实现网页多种语言切换 时间:2016-11-11 浏览次数:1120 编辑:youjiejie   网页如何设计多种语言切换,本文用tp框架实现网页多种语言切换方法结合实例形式较为详细的分析 ...