java nio 基础之Buffer 用法

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 stub
		ChannelModelSelectDemo 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 stub
		FileCopyUtil 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:1024
file 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();
		
        //定义缓存区大小--one
		ByteBuffer bufferone = ByteBuffer.allocate(48);
		//定义缓存区大小--two
		ByteBuffer 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 stub
		FileScatterGather 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 stub
		TwoFileChannelTrans util = new TwoFileChannelTrans("D:\\demo.txt", "D:\\one.txt");
		boolean target = util.copy();
		System.out.println("file copy is successful:"+target);
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值