buffer java nio_Java NIO深入理解Buffer(缓冲区)

前言

Github:https://github.com/yihonglei/java-all

Project:java-nio

一 Buffer概述

Java NIO中的Buffer用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的。

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,

并提供了一组方法,用来方便的访问该块内存。

二 Buffer重要知识点分析

1、Buffer基本用法

使用Buffer读写数据一般遵循以下四个步骤:

1)写入数据到Buffer,一般有可以从Channel读取到到缓冲区中,也可以调用put方法写入。

2)调用flip()方法,切换数据模式。

3)从Buffer中读取数据,一般从缓冲区读取数据写入到通道中,也可以调用get方法读取。

4)调用clear()方法或者compact()方法清空缓冲区。

当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。

在读模式下,可以读取之前写入到buffer的所有数据。一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。

有两种方式能清空缓冲区:

1)clear()方法会清空整个缓冲区。

2)compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区

未读数据的后面。

package com.lanhuigu.nio.buffer;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

/**

* 使用Buffer读写数据一般遵循以下四个步骤:

* (1)写入数据到Buffer,一般有可以从Channel中读取到缓冲区,也可以调用put方法写入。

* (2)调用flip()方法,切换数据模式。

* (3)从Buffer中读取数据

* (4)调用clear()方法或者compact()方法

* 当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。

* 在读模式下,可以读取之前写入到buffer的所有数据。一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。

*

* 有两种方式能清空缓冲区:

* 1)clear()方法会清空整个缓冲区。

* 2)compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。

*/

public class BufferRWTest {

/**

* 文件复制实例

*/

public static void main(String[] args) {

// 源文件

File fromFile = new File("C:\\mycode\\hello.txt");

// 目标文件

File toFile = new File("C:\\mycode\\hello-copy.txt");

try (

// 根据源文件创建文件输入流

FileInputStream fis = new FileInputStream(fromFile);

// 根据目标文件创建文件输出流,如果文件不存在,自动创建

FileOutputStream fos = new FileOutputStream(toFile);

// 1. 获取通道

FileChannel inChannel = fis.getChannel();

FileChannel outChannel = fos.getChannel();

) {

// 2. 分配指定大小的缓冲区

ByteBuffer buffer = ByteBuffer.allocate(48);

// 3. 将通道中的数据读取到缓冲区

while (inChannel.read(buffer) != -1) {

// 切换成读数据模式

buffer.flip();

// 4. 从缓冲区读取数据写入到通道中

outChannel.write(buffer);

// 清空缓冲区

buffer.clear();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

2、Buffer的capacity、position和limit

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,

并提供了一组方法,用来方便的访问该块内存。为了理解Buffer的工作原理,需要熟悉它的三个属性:

.capacity

.position

.limit

position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。

这里有一个关于capacity,position和limit在读写模式中的说明:

42705e543d9f7d7683812dc13b5c2681.png

capacity

作为一个内存块,Buffer有一个固定的大小值,也叫"capacity"。你只能往里写capacity个byte、long,char等类型。

一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

position

当你写数据到Buffer中时,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。

3、Buffer的类型

如下是Java NIO中最重要的缓冲区的实现:

ByteBuffer

CharBuffer

DoubleBuffer

FloatBuffer

IntBuffer

LongBuffer

ShortBuffer

MappedByteBuffer

这些Buffer覆盖了你能通过IO发送的基本数据类型:byte, short, int, long, float, double和char。

4、Buffer的分配

要想获得一个Buffer对象首先要进行分配。每一个Buffer类都有一个allocate方法。

分配48字节capacity的ByteBuffer的例子:

ByteBuffer buf = ByteBuffer.allocate(48);

分配一个可存储1024个字符的CharBuffer:

CharBuffer buf = CharBuffer.allocate(1024);

5、向Buffer中写入数据

写数据到Buffer有两种方式:

1)从Channel写到Buffer。

2)通过Buffer的put()方法写到Buffer里。

从Channel写到Buffer的例子:

int bytesRead = inChannel.read(buf); // 从Channel(通道)读取到Buffer(缓冲区)中

通过put方法写Buffer的例子:

buf.put(127);

put方法有很多版本,允许你以不同的方式把数据写入到Buffer中。

例如,写到一个指定的位置,或者把一个字节数组写入到Buffer。

6、flip()方法使用

flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

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

7、从Buffer中读取数据

从Buffer中读取数据有两种方式:

1)从Buffer读取数据到Channel。

2)使用get()方法从Buffer中读取数据。

从Buffer读取数据到Channel的例子:

// 从Buffer中读取数据写入到通道中

int bytesWritten = inChannel.write(buf);

使用get()方法从Buffer中读取数据的例子:

byte aByte = buf.get();

get方法有很多版本,允许你以不同的方式从Buffer中读取数据。

例如,从指定position读取,或者从Buffer中读取数据到字节数组。

8、rewind()方法

Buffer.rewind()将position设回0,所以你可以重读Buffer中的所有数据。

limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)。

9、clear()和compact()方法

一旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成。

如果调用的是clear()方法,position将被设回0,limit被设置成capacity的值。换句话说,Buffer被清空了。

Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。如果Buffer中有一些未读的数据,

调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。

如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先写些数据,那么使用compact()方法。

compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。

limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。

10、mark()和reset()方法

通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。

之后可以通过调用Buffer.reset()方法恢复到这个position。例如:

buffer.mark();

//调用buffer读写方法,下面通过调用reset恢复到调用前的position位置。

buffer.reset(); // set position back to mark

11、equals()和compareTo()方法

可以使用equals()和compareTo()方法两个Buffer。

equals()

当满足下列条件时,表示两个Buffer相等。

1)有相同的类型(byte、char、int等)。

2)Buffer中剩余的byte、char等的个数相等。

3)Buffer中所有剩余的byte、char等都相同。

如你所见,equals只是比较Buffer的一部分,不是每一个在它里面的元素都比较。

实际上,它只比较Buffer中的剩余元素。

compareTo()

compareTo()方法比较两个Buffer的剩余元素(byte、char等),如果满足下列条件,则认为一个Buffer"小于"另一个Buffer。

1)第一个不相等的元素小于另一个Buffer中对应的元素。

2)所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/442405.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java robot键值_Java:使用Robot类模拟键盘, 以Alt码方式输出汉字

java.awt.Robot类Java提供java.awt.Robot类来模拟操作键盘和鼠标, 下面是一个简单的demopublic static void keyPressByInt(Robot r,int key, int time){r.keyPress(key);r.keyRelease(key);if (time > 0) {r.delay(time);}}public static void main(String[] args) throws …

java调用 火眼臻睛,火眼臻睛车牌识别SDK评测

【CPS中安网 cps.com.cn】CPS LAB总评:用专业角度解读产品--CPS评测中心对火眼臻睛车牌识别SDK进行了全面评测,火眼臻睛车牌识别SDK在综合识别率、车牌定位成功率、大角度下的识别率、夜间环境下的识别率、极端环境下的识别率、支持的最小车牌像素宽度等测试表现,都位于行业前列…

java各层级限流对比,面试官说:来谈谈限流-从概念到实现,一问你就懵逼了?...

后端服务的接口都是有访问上限的,如果外部qps或并发量超过了访问上限会导致应用瘫痪。所以一般都会对接口调用加上限流保护,防止超出预期的请求导致系统故障。从限流类型来说一般来说分为两种:并发数限流和qps限流,并发数限流就是限制同一时刻…

mysql and 和where,关于mysql:连接sql查询中where和and子句的区别

本问题已经有最佳答案,请猛点这里访问。下面两个SQL查询有什么区别和号根据以下两个测试结果速度更快(237比460)。据我所知,这是一个标准。。氧化镁不,有细微的差别,你不能说没有差别除了语法之外没有别的区别。虽然只有一个简短的…

matlab里输出恒压的逆变器,基于IGBT逆变器的异步电机变频调速系统的MATLAB仿真...

异步电机变频调速系统电路仿真模型如图(4)所示。直流电压不621V,逆变器为IGBT 的三相半桥逆变器,电机为异步电机模块,其主电路由直流电压源、逆变器和电机依次相连。图(4)变频调速系统控制部分,利用“Step”模块设定频率指令f1*&a…

php 获取京东交易账号,PHP爬虫爬取京东列表

这里使用到了一个php插件下面是源码simple_html_dom.phpdefined(IN_ECS);define(HDOM_TYPE_ELEMENT, 1);define(HDOM_TYPE_COMMENT, 2);define(HDOM_TYPE_TEXT, 3);define(HDOM_TYPE_ENDTAG, 4);define(HDOM_TYPE_ROOT, 5);define(HDOM_TYPE_UNKNOWN, 6);define(HDOM_QUOTE_DOU…

php dns刷新,Windows DNS缓存自动刷新

Windows DNS缓存自动刷新admin • 2018 年 09 月 04 日DNS(域名服务器)DNS(Domain Name Server)是进行域名和与之相对应的ip地址转换的服务器。DNS中保存了一张域名和与之相应的ip地址的表,以解析消息的域名。DNS轮训在统一主机添加多条A记录,这就是DNS轮…

jq上传file到php,jQuery文件上传

插件描述:这是一个文件上传的展示,看很多插件,并不满意就自己写了一个,可能兼容性不是很好,没有准确进行测试过,还请各位不吝赐教更新时间:2019/3/25 下午8:53:17更新说明:修复上传成…

linux误删表空间文件,UNDO表空间下的数据文件被误删除后的处理方法

UNDO表空间下的数据文件被误删除后的处理方法:操作前备份数据库,以避免更大的损失。思路:1、把误删除的数据文件offline2、正常打开数据库后创建新的UNDO表空间及数据文件3、修改相应参数指向新的UNDO表空间4、重新启动数据库验证5、删除旧的…

linux内核有ebpf吗,聊聊很重要的内核技术eBPF

在2018年的 Linux Plumber 大会上,eBPF成了亮点,有24个议题提到了 eBPF,可以预计eBPF会成为一大技术热点。eBPF(Extended Berkeley Packet Filter) 的核心是驻留在 kernel 的高效虚拟机。最初的目的是高效网络过滤框架,前身是 BPF…

oom linux 导致ssh,Linux OOM

8种机械键盘轴体对比本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?某个机器看到一条日志:Out of Memory: Kill process xxx (xxx) score 707 or sacrifice child并且syslog, ssh等进程都被kill掉了.简单了解了下OOM(Out of Memory)…

c语言bfs程序讲解,面试算法--二叉树DFS/BFS实现(C语言)

深度优先搜索算法(Depth First Search)DFS是搜索算法的一种。它沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还…

c语言 子进程,子Shell和子进程

Shell 中有很多方法产生子进程,比如以新进程的方式运行 Shell 脚本,使用组命令、管道、命令替换等,但是这些子进程是有区别的。子进程的概念是由父进程的概念引申而来的。在 Linux 系统中,系统运行的应用程序几乎都是从 init(pid为…

学C语言办公本和游戏本,为什么不建议买游戏本?入手前须知,别只看中游戏...

原标题:为什么不建议买游戏本?入手前须知,别只看中游戏作为一名游戏本用户,我自己在用的游戏本已经用了四五年的时间了,从最初的大学生到毕业工作2年时间,这一游戏本给我带来了不少麻烦。最大的麻烦就是“笨…

Android ui 单元测试 覆盖率,Android单元测试—UI测试(Espresso)

前言我们先回顾一下,在上一篇博客中,主要分享了Android单元测试的逻辑测试部分。接下来,我们重点讲解Android单元测试的UI测试部分!何为UI测试呢?就是对用户界面的交互元素进行测试,如TextView、ImageView&…

android shape 圆角百分比,Android shape显示圆角问题

当需要定义一个圆角效果,当在ADT中预览,没有有效果时,只要运行就可以了!xmlns:Android"http://schemas.android.com/apk/res/android">android:state_pressed"true">android:startColor"#ff8c00"android:endColor"#FFFFFF…

android 删除垃圾文件夹,别再用手机管家清理垃圾了!删除这些文件夹,内存瞬间释放几个G...

随着手机使用时间的增加,手机中缓存的东西越来越多,这时候手机内存空间就会告急,从而影响手机的流畅性。那么在这种时候不要乱清理,我们只需要删除这几个文件夹,就可以帮手机轻松释放好几个G的内存。下面我们就一起来看…

计算机的应用技术课程的看法,统计教学与计算机应用的几点看法论文

统计教学与计算机应用的几点看法论文一、传统教学方法的局限性和弊端统计学是一门关于搜集、整理、汇总、描述和分析数据资料,并在此基础上进行推断和决策的方法论科学,具有很强的应用性、实践性。统计学课程是中等职业学校、财经类专业的基础核心课程。…

jupyter可以打开HTML文件吗,Jupyter ~ 像写文章般的 Coding (附:同一个ipynb文件,执行多语言代码)...

前面用了很久Notebook来交互式编程了,此次说说几个其余的选项:htmlNotebook Markdown此次选Markdown模式(关于Markdown基础能够看以前写的Markdown Base)python和代码同样,Shift回车就能够预览了,怎么样是否是很酷的感受&#xff…

计算机网络技术基础教学内容,计算机网络技术基础

无计算机网络技术基础》课程教案一 计算机网络技术基础》课题: 课题:计算机网络概述(一) ) 教学顺序: 教学顺序:1 教学时数: 教学时数: 2 学时 教学目的:了解计算机网络产生的背景,掌…