NIO入门 - 缓存与映射

1 篇文章 0 订阅

NIO归根结底就是使用通道的缓存与映射,以实现输入源与输出源的操作简化

此篇不涉及Web端的NIO开发(选择器/就绪加载/管道)

要想理解NIO的缓存机制,就必须要了解三个参数:

参数含义
capacity缓冲区数组的总长度
position下一个要操作的数据元素的位置
limit缓冲区数组中限制长度的下一个位置:limit<=capacity

而通道本身是用以下方法操作参数的:

方法名(Buffer含义
ByteBuffer.allocate(1024)生成/分配Buffer的空间大小
hasRemaining()检查当前位置与限制之间是否有元素
filp()读取与写入转换/其实就是限制长度和将position设置为0
clear()重置缓存区/归根结底就是重置上面的三个参数(和硬盘快速格式化原理差不多)
compact()清除已读数据,将未读数据提前,新写入的数据将放在未读数据后面
get()从Buffer中获取一定长度的数组
put()往Buffer中添加一定长度的数组
方法名(Channel含义
read(Buffer)将数据读到Buffer中
write(Buffer)将Buffer的数据写入Channel中
transferFrom(inputChannel,起始位置,长度)将数据读取到inputChannel中
transferTo(起始位置,长度,outputChannel)将数据写入outputChannel中
map(MapMode,起始位置,长度)将这段数据映射到内存中

附加功能

MapMode含义
READ_ONLY只读方式打开
READ_WEITE读写模式,修改将直接映射到源文件
PRIVATE专有模式,修改不会映射到源文件
方法名(Channel含义
lock()文件锁,顾名思义

字符转换

Charset cs = Charset.forName("UTF-8");//转为UTF-8格式
CharBuffer charbuffer = cs.decode(buffer);//先解析为Char
return cs.encode(charbuffer);//再编码为字节

附上文件复制代码

/** 普通缓存拷贝 */
public static void copyNio(File file, File toFile) throws IOException{
		FileInputStream fis = null;
		FileOutputStream fos = null;
		FileChannel inChannel = null;
		FileChannel outChannel = null;
		try {
			fis = new FileInputStream(file);
			fos = new FileOutputStream(toFile);
			inChannel = fis.getChannel();
			outChannel = fos.getChannel();
			long start = System.currentTimeMillis();
			ByteBuffer buffer = ByteBuffer.allocate(0x100000);//创建缓存区
			while(inChannel.read(buffer) != -1){//读取缓存区长度的数据(-1表示无数据)
				buffer.flip();//重置position
				outChannel.write(buffer);//写入position至limit中间的数据
				buffer.flip();//重置position
			}
			long stop = System.currentTimeMillis();
			System.out.println("nio:" + (stop-start));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(fis != null)
				fis.close();
			if(fos != null)
				fos.close();
			if(inChannel != null)
				inChannel.close();
			if(outChannel != null)
				outChannel.close();
		}
		
	}
	
	/** 内存映射拷贝 */
	public static void copyNioMapper(File file, File toFile) throws IOException, FileException{
		//if(file.length() > ((long)1 << 32)) throw new FileException("文件大于两个G");
		FileInputStream fis = null;
		FileOutputStream fos = null;
		FileChannel inChannel = null;
		FileChannel outChannel = null;
		MappedByteBuffer rb = null;
		long SIZE = (long)1 << 30;//设置每个映射缓存为1G
		try {
			fis = new FileInputStream(file);
			fos = new FileOutputStream(toFile);
			inChannel = fis.getChannel();
			outChannel = fos.getChannel();
			long start = System.currentTimeMillis();
			while(inChannel.position() != inChannel.size()){
				if((inChannel.size() - inChannel.position()) < SIZE){//如果文件剩余大小小于1G
					SIZE = (int) (inChannel.size() - inChannel.position());
				}
				rb = inChannel.map(MapMode.READ_ONLY, inChannel.position(), SIZE);//映射文件缓存
				outChannel.write(rb);//直接写入
				inChannel.position(inChannel.position() + SIZE);//设置inChannel的position
			}
//			rb = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
//			outChannel.write(rb);
			long stop = System.currentTimeMillis();
			System.out.println("nioMapper:" + (stop-start));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(rb != null)
				rb.clear();
			if(inChannel != null)
				inChannel.close();
			if(outChannel != null)
				outChannel.close();
			if(fis != null)
				fis.close();
			if(fos != null)
				fos.close();
		}
		
	}

得出的结果是内存映射干不过缓存。。无论内存映射容量调节到多少,都干不过缓存,我怀疑我遇到了一个假的内存映射。。内存映射应该有更广的用途,复制文件什么的,缓存就足够了

代码案例里面没有涉及到get()/put()和transferFrom()/transferTo(),仅仅是文件复制的话不需要提高数据获取的精度,如果之后需要获取网络头信息啥的就会涉及。

实验环境:JDK1.8

后续更新。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值