java nio 基础之Buffer 用法

来源:互联网 发布:预约学车软件 编辑:程序博客网 时间:2024/06/01 10:26

java nio  Buffer的本质是“数据通过通道写入缓存区中,从缓存中读取数据到通道中”。


总结Buffer 基本用法(本段参考至:Java NIO系列教程(三)Buffer)

1、写入数据到Buffer

2、调用filp(),实现读取模式和写入模式切换

3、读取Buffer 数据

4、调用clear()或者compact()方法,清理已经读取的相关信息。


对于以上步骤有一个详细版本讲解:

1、当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。

2、一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用clear()或compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。


简单的demo 实例:将‘demo.txt’文本中的内容写入缓存中,读取缓存中的内容,使用filp()切换(读写模式)方法,再次使用通道是否还可以读取缓存中的数据信息。

package com.nio.one;import java.io.File;import java.io.FileInputStream;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;public class ChannelModelSelectDemo {private String path;private Boolean bool;public ChannelModelSelectDemo(String path, Boolean bool) {this.path = path;this.bool = bool;}public Boolean getBool() {return bool;}public void setBool(Boolean bool) {this.bool = bool;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public static void main(String[] args) throws Exception {// TODO Auto-generated method stubChannelModelSelectDemo demo = new ChannelModelSelectDemo("D:\\demo.txt", true);FileInputStream in = new FileInputStream(new File(demo.path));FileChannel inChannel = in.getChannel();ByteBuffer buffer = ByteBuffer.allocate(24);// 通过通道将数据读取到缓存中int num = inChannel.read(buffer);while (num != -1) {// buffer 读写模式进行切换(切换为读取模式)buffer.flip();// 读取已经写入缓存的数据System.out.println("读取内容是:" + new String(buffer.array()));// 清空已经读取到buffer 缓存中的数据(切换为写入模式)buffer.clear();// 通过通道将数据写入缓存中num = inChannel.read(buffer);}inChannel.close();in.close();}}


Buffer 的三大属性值:capacity、position和limit

java nio 中的Buffer,在我的眼中看:“Buffer 只是一块既可以读取数据也可以写入数据的缓存地址空间”。

下面关于Buffer 三大属性值的描述参考:Java NIO 系列教程(三) Buffer


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

这里有一个关于capacity,position和limit在读写模式中的说明,详细的解释在插图后面。


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)


demo 实例:输出创建数据缓存三大属性,输出数据缓存写入模式式三大属性值,输出数据缓存读取模式三大属性值。

package com.nio.one;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;public class FileCopyUtil {private String to;private String from;public FileCopyUtil(String to, String from) {this.to = to;this.from = from;}public String getTo() {return to;}public void setTo(String to) {this.to = to;}public String getFrom() {return from;}public boolean copy() throws Exception {boolean target = false;FileInputStream in = new FileInputStream(new File(this.to));FileOutputStream out = new FileOutputStream(new File(this.from));//获取文件读取通道FileChannel inChannel = in.getChannel();//获取文件写入通道FileChannel outChannel = out.getChannel();        //定义缓存区大小ByteBuffer buffer = ByteBuffer.allocate(1024);System.out.println("创建缓存数据capacity size is:"+buffer.capacity());System.out.println("创建缓存数据position size is:"+buffer.position());System.out.println("创建缓存数据limit size is:"+buffer.limit());while (true) {// 清空缓存空间buffer.clear();//读取数据到缓存区int num = inChannel.read(buffer);System.out.println("缓存数据读取模式capacity size is:"+buffer.capacity());System.out.println("缓存数据读取模式position size is:"+buffer.position());System.out.println("缓存数据读取模式limit size is:"+buffer.limit());if (num == -1) {break;}//将buffer 指针指向头部buffer.flip();//将缓存数据写入通道outChannel.write(buffer);System.out.println("缓存数据写入模式capacity size is:"+buffer.capacity());System.out.println("缓存数据写入模式position size is:"+buffer.position());System.out.println("缓存数据写入模式limit size is:"+buffer.limit());}target = true;return target;}public void setFrom(String from) {this.from = from;}public static void main(String[] args) throws Exception {// TODO Auto-generated method stubFileCopyUtil util = new FileCopyUtil("D:\\demo.txt", "D:\\one.txt");boolean target = util.copy();System.out.println("file copy is successful:"+target);}}

输出结果:

创建缓存数据capacity size is:1024创建缓存数据position size is:0创建缓存数据limit size is:1024缓存数据读取模式capacity size is:1024缓存数据读取模式position size is:166缓存数据读取模式limit size is:1024缓存数据写入模式capacity size is:1024缓存数据写入模式position size is:166缓存数据写入模式limit size is:166缓存数据读取模式capacity size is:1024缓存数据读取模式position size is:0缓存数据读取模式limit size is:1024file copy is successful:true


Buffer对象分配:每个继承自Buffer类的子类都有一个allocate方法。

示例代码一:分配一个48字节大小的ByteBuffer.

ByteBuffer   buffer = ByteBuffer.allocate(48);

示例代码二:分配一个1024字符大小的CharBuffer.

CharBuffer buffer = CharBuffer.allocate(1024);



Buffer 读取数据方式:

第一种:通过channel.read(buffer)方法。

示例代码: filerChannel.read(buffer)       //这句代码的意思是:文件通道将读取到的数据存入buffer缓存数据中。


第二种:通过buffer.put()方法。

示例代码:buffer.put("传递参数");           //这句代码的意思是:向buffer缓存数据中put(添加)相关数据;



Buffer 写入数据方式:

第一种:通过channel.write(buffer)方法。

示例代码:fileChannel.write(buffer)        //这句话的意思是:buffer缓存中的数据,通过文件管道写入指定位置。


第二种:通过buffer.get()方法

示例代码:buffer.get();                           //这句代码的意思是:通过get方法获取buffer中的缓存数据。



Buffer 的scatter 和  gather

Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作。
分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中。因此,Channel将从Channel中读取的数据“分散(scatter)”到多个Buffer中。
聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel,因此,Channel 将多个Buffer中的数据“聚集(gather)”后发送到Channel。


scatter / gather经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息,你可能会将消息体和消息头分散到不同的buffer中,这样你可以方便的处理消息头和消息体。


Scattering Reads

Scattering Reads是指数据从一个channel读取到多个buffer中。如下图描述:



Gattering Writes

Gathering Writes是指数据从多个buffer写入到同一个channel。如下图描述:



示例代码:通过sactter和gather,完善并且修改文件CopyUtil .java 代码。

package com.nio.one;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;public class FileScatterGather {private String to;private String from;public FileScatterGather(String to, String from) {this.to = to;this.from = from;}public String getTo() {return to;}public void setTo(String to) {this.to = to;}public String getFrom() {return from;}public boolean copy() throws Exception {boolean target = false;FileInputStream in = new FileInputStream(new File(this.to));FileOutputStream out = new FileOutputStream(new File(this.from));//获取文件读取通道FileChannel inChannel = in.getChannel();//获取文件写入通道FileChannel outChannel = out.getChannel();        //定义缓存区大小--oneByteBuffer bufferone = ByteBuffer.allocate(48);//定义缓存区大小--twoByteBuffer buffertwo = ByteBuffer.allocate(48);//定义缓存数组大小ByteBuffer[] bufferArray = { bufferone, buffertwo };while (true) {// 清空缓存空间bufferone.clear();buffertwo.clear();//读取数据到缓存区    long num = inChannel.read(bufferArray);if (num == -1) {break;}//将buffer 指针指向头部bufferone.flip();buffertwo.flip();//将缓存数据写入通道outChannel.write(bufferArray);}target = true;return target;}public static void main(String[] args) throws Exception {// TODO Auto-generated method stubFileScatterGather util = new FileScatterGather("D:\\demo.txt", "D:\\one.txt");boolean target = util.copy();System.out.println("file copy is successful:"+target);}}
今天在回顾java.nio 基础知识时参考:Java NIO 基础教程,发现自己漏看了一个《通道数据之间的传递》。

在这里重新补充一下:通道传递:简单的来说就是两个通过之间的数据传递,实现的方法主要是channel.transferFrom()和channel.transferTo.

通道类存在这么简单的方法,我们的目标持续调整,我修改我之间FileCopy.java (文件拷贝)类,通过通道之间的数据传递实现文件拷贝功能。

实例代码:

package com.nio.one;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;public class TwoFileChannelTrans {private String to;private String from;public TwoFileChannelTrans(String to, String from) {this.to = to;this.from = from;}public String getTo() {return to;}public void setTo(String to) {this.to = to;}public String getFrom() {return from;}public boolean copy() throws Exception {boolean target = false;FileInputStream in = new FileInputStream(new File(this.to));FileOutputStream out = new FileOutputStream(new File(this.from));//获取文件读取通道FileChannel inChannel = in.getChannel();//获取文件写入通道FileChannel outChannel = out.getChannel();long position  = 0;long count = inChannel.size();//通道之间写入//inChannel.transferTo(position, count, outChannel);//通道之间读取outChannel.transferFrom(inChannel, position, count);target = true;return target;}public void setFrom(String from) {this.from = from;}public static void main(String[] args) throws Exception {// TODO Auto-generated method stubTwoFileChannelTrans util = new TwoFileChannelTrans("D:\\demo.txt", "D:\\one.txt");boolean target = util.copy();System.out.println("file copy is successful:"+target);}}



原创粉丝点击