JAVA NIO系列(三) Buffer 解读
缓冲区分类
NIO中的buffer用于和通道交互,数据是从通道读入缓冲区,从缓冲区中写入通道的。Buffer就像一个数组,可以保存多个类型相同的数据。每种基本数据类型都有对应的Buffer类:
缓冲区的属性
1、capacity(容量):buffer本质是一个数组,在初始化时有固定的大小,这个值就是容量。容量不可改变,一旦缓冲区满了,需要将其清空才能将继续进行读写操作。
2、position(位置):表示当前的位置,初始化时为0,当一个基本数据类型的数据写入buffer时,position会向前移动到下一个可插入数据的Buffer单元。position最大值可以是 capacity-1。
3、limit(限制):在缓冲区写模式下,limit表示你最多能往Buffer里写多少数据,大小等于capacity;在缓冲区读模式下,limit表示能从缓冲区内读取到多少数据,因此,当切 换Buffer到读模式时,limit会被设置成写模式下的position值。
一、使用NIO进行文件内容的复制:
public class BufferTest
{
public static void main(String[] args) throws Exception
{
FileInputStream fis = new FileInputStream("d:/in.txt");
FileChannel channel = fis.getChannel(); FileOutputStream fos = new FileOutputStream("d:/out.txt");
FileChannel channel1 = fos.getChannel();
//初始化缓冲区
ByteBuffer buffer = ByteBuffer.allocate(20);
System.out.println("通道文件的大小:" + channel.size());
System.out.println("缓冲区初始化时当前位置:" + buffer.position());
System.out.println("缓冲区初始化时可写的限制:" + buffer.limit());
System.out.println("---------循环开始-----");
//判断通道内数据是否读取完成
while(-1 != channel.read(buffer))
{
System.out.println("缓冲区写模式下当前位置:" + buffer.position());
System.out.println("缓冲区写模式下的限制:" + buffer.limit());
//将缓冲区从写模式切换到读模式
buffer.flip();
System.out.println("缓冲区读模式下当前位置:" + buffer.position());
System.out.println("缓冲区读模式下的限制:" + buffer.limit());
//判断缓冲区内是否还有数据可读取
while(buffer.hasRemaining())
{
channel1.write(buffer);
}
buffer.clear();
}
channel.close();
channel1.close();
fis.close();
}
}
执行结果:
通道文件的大小:36
缓冲区初始化时当前位置:0
缓冲区初始化时可写的限制:20
---------循环开始-----
缓冲区写模式下当前位置:20
缓冲区写模式下的限制:20
缓冲区读模式下当前位置:0
缓冲区读模式下的限制:20
缓冲区写模式下当前位置:16
缓冲区写模式下的限制:20
缓冲区读模式下当前位置:0
缓冲区读模式下的限制:16
1、文件的大小为36个字节,缓冲区初始化的大小为20个字节,程序中进行了两次读取操作,才完成了文件内容的复制。
2、可以看到,在缓冲区写模式下,limit的大小始终等于capacity;而在读模式下,limit等于模式切换前position的大小。
二、Buffer的分配
Buffer对象的获取需要进行分配,每种类型的Buffer对象都有一个allocate方法。我们以程序中的ByteBuffer对象为例:
ByteBuffer buffer = ByteBuffer.allocate(20);
我们去跟踪下源码:
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
HeapByteBuffer(int cap, int lim) { // package-private super(-1, 0, lim, cap, new byte[cap], 0);
//在这里已经创建一个以cap为大小的字节数组(new byte[cap])
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;
}
Buffer(int mark, int pos, int lim, int cap) { // package-private
if (cap < 0)
throw new IllegalArgumentException();
this.capacity = cap;
limit(lim);
position(pos);
if (mark >= 0) {
if (mark > pos)
throw new IllegalArgumentException();
this.mark = mark;
}
}
//数组的创建在ByteBuffer类里面已经创建,在父类Buffer里,初始化容量、限制、位置等一些公共属性。
三、Buffer模式的切换
buffer.flip()该方法是用于将缓冲区从写模式切换到读模式,这是一种固定写法,该方法的源码如下:
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
调用flip()方法会将position设回0,并将limit设置成之前position的值。
四、remaind方法
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
将position的位置设置为0,表示可以重新读取Buffer中的所有数据,limit保持不变。
五、clear方法
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
1、一旦完成对buffer中数据的读取,需要让buffer做好再次被写入的准备,这时候可以调用clear方法来完成。
2、clear方法将position设置为0,limit设置为容量的值,也就意味着buffer被清空了,但是这个清空的概念是写入数据可以从缓冲区的指定位置开始,但buffer里面的数据并没有 删除。
3、如果buffer里面还有数据没有被读取,这个时候调用clear方法会导致那些数据被“遗忘”,因为没有标记告诉你哪些是读取过哪些没有被读取。
六、向buffer中写入数据
1、通过channel写入;
2、通过buffer的put方法写入:
buffer.put("channel".getBytes());
七、从buffer中读取数据
1、通过channel读取;
2、通过buffer的get方法读取:
byte b = buffer.get();
JAVA NIO系列(三) Buffer 解读的更多相关文章
- Java NIO系列教程(三-十二) Buffer
原文链接 作者:Jakob Jenkov 译者:airu 校对:丁一 Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到 ...
- 转:Java NIO系列教程(三) Buffer
Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的. 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被包装成NIO ...
- Java NIO系列教程(三) Buffer(转)
Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的. 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被包装成NIO ...
- Java NIO系列教程(三) Buffer
Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的.交互图如下: 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被 ...
- Java NIO系列教程(三) Channel之Socket通道
目录: <Java NIO系列教程(二) Channel> <Java NIO系列教程(三) Channel之Socket通道> 在<Java NIO系列教程(二) Ch ...
- Java NIO系列教程(五)Buffer
Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的.交互图如下: 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被 ...
- Java NIO(三) Buffer
Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的. 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被包装成NIO ...
- Java NIO 系列教程(转)
原文中说了最重要的3个概念,Channel 通道Buffer 缓冲区Selector 选择器其中Channel对应以前的流,Buffer不是什么新东西,Selector是因为nio可以使用异步的非堵塞 ...
- Java NIO系列1-概观
Java NIO系列1-概观 Java NIO.中间的N你既可以理解为(new),也就是新的IO,相对于java1.5之前的IO它确实是新的;也可以理解为(no-blocking),也就是非阻塞的IO ...
- Java NIO系列教程(八)JDK AIO编程
目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...
随机推荐
- 推荐25款php中非常有用的类库
推荐25款php中非常有用的类库 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2014-09-29 作为一个PHP开发者,现在是一个令人激动的时刻.每天有许许多多有用的库分发出 ...
- navicat for mysql 10.1.7注册码
终于找到一个可用的了:名,组织,注册码都是:NAVN-LNXG-XHHX-5NOO 还有一个 注册码:NAVH-WK6A-DMVK-DKW3名称和组织不用填写 好像都可以用
- url如何传递参数
$(document).ready(function() { var name=getQueryString('minename'); if (name != null && name ...
- (转)android 在电脑上显示真机屏幕
http://my.oschina.net/u/202293/blog/199954 方法一: 可以用360手机助手等实现. 方法二: 想把手机屏幕显示在电脑屏幕上时就需要使用Android Scre ...
- C#窗体:关于DataGridView的数据源绑定字符串两个值得注意的问题
无意间遇到的问题,然后就GOOGLE了下,搜到些资料,总结整理如下(注:是转载的) 1. LINQ的查询结果无法直接作为DataGridView的数据源 DataGridView的DataSource ...
- Linq分组功能
Linq在集合操作上很方便,很多语法都借鉴自sql,但linq的分组却与sql有一定的区别,故整理发布如下. 1. Linq分组 分组后以Key属性访问分组键值. 每一组为一个IEnumberAbl ...
- 创建数据库指定路径sql
create database stuDB on primary -- 默认就属于primary文件组,可省略(/*--数据文件的具体描述--*/ name='stuDB_data', - ...
- php--城市分类
效果图:
- backbone 更新1.1.2
backbone已经更新到1.1.2,在这里总结一下 我还一直用的1.0的版本,更新确实出现了一些问题 1.1.0 Backbone Views no longer automatically at ...
- linux 开机启动设置
操作系统:Ubuntu12.04硬件环境:HP CQ45 当用户使用sudo apt-get install安装完apache和mysql之后,这些服务默认是开机启动的,但是有的时候需要 ...